Merge branch 'documentation' into 'master'
Documentation and minor reformattings Closes #27 and #35 See merge request lukas/openmediacenter!11
This commit is contained in:
commit
f0902d29b7
16
README.md
16
README.md
@ -8,14 +8,18 @@ Feel free to contribute or open an issue here: https://gitlab.heili.eu/lukas/ope
|
|||||||
## What is this?
|
## What is this?
|
||||||
Open Media Center is an open source solution for a mediacenter in your home network.
|
Open Media Center is an open source solution for a mediacenter in your home network.
|
||||||
Transform your webserver into a mediaserver.
|
Transform your webserver into a mediaserver.
|
||||||
It's based on Reactjs and PHP is used as backend.
|
It's based on Reactjs and PHP is used for backend.
|
||||||
It is optimized for general videos as well as for movies.
|
It is optimized for general videos as well as for movies.
|
||||||
For grabbing movie data TMDB is used.
|
For grabbing movie data TMDB is used.
|
||||||
For organizing videos tags are used.
|
With the help of tags you can organize your video gravity.
|
||||||
|
|
||||||
Here you can see an example main page:
|
Here you can see an example main page in light mode:
|
||||||
|
|
||||||
![Image of OpenMediaCenter](https://i.ibb.co/2PC3fmk/Screenshot-20200604-163448.png)
|
![Image of OpenMediaCenter](https://i.ibb.co/pnDjgNT/Screenshot-20200812-172945.png)
|
||||||
|
|
||||||
|
and in dark mode:
|
||||||
|
|
||||||
|
![](https://i.ibb.co/xzhdsbJ/Screenshot-20200812-172926.png)
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
First of all clone the repository.
|
First of all clone the repository.
|
||||||
@ -32,9 +36,9 @@ You need also to setup a Database with the structure described in [SQL Style Ref
|
|||||||
The login data to this database needs to be specified in the `api/Database.php` file.
|
The login data to this database needs to be specified in the `api/Database.php` file.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
To index Videos run on your server: `php extractvideopreviews.php`.
|
Now you can access your MediaCenter via your servers global ip (:
|
||||||
|
|
||||||
Now you can access your MediaCenter via the servers global ip (:
|
At the settings tab you can set the correct videopath on server and click reindex afterwards.
|
||||||
|
|
||||||
## Contact
|
## Contact
|
||||||
Any contribution is appreciated.
|
Any contribution is appreciated.
|
||||||
|
30
api/Tags.php
30
api/Tags.php
@ -1,30 +0,0 @@
|
|||||||
<?php
|
|
||||||
require_once 'RequestBase.php';
|
|
||||||
|
|
||||||
class Tags extends RequestBase {
|
|
||||||
function initHandlers() {
|
|
||||||
$this->addActionHandler("getAllTags", function () {
|
|
||||||
$query = "SELECT tag_name,tag_id from tags";
|
|
||||||
|
|
||||||
$result = $this->conn->query($query);
|
|
||||||
$rows = array();
|
|
||||||
while ($r = mysqli_fetch_assoc($result)) {
|
|
||||||
array_push($rows, $r);
|
|
||||||
}
|
|
||||||
echo json_encode($rows);
|
|
||||||
});
|
|
||||||
|
|
||||||
$this->addActionHandler("createTag", function (){
|
|
||||||
$query = "INSERT INTO tags (tag_name) VALUES ('" . $_POST['tagname'] . "')";
|
|
||||||
|
|
||||||
if ($this->conn->query($query) === TRUE) {
|
|
||||||
echo('{"result":"success"}');
|
|
||||||
} else {
|
|
||||||
echo('{"result":"' . $this->conn->error . '"}');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$tags = new Tags();
|
|
||||||
$tags->handleAction();
|
|
@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
require 'Database.php';
|
require_once './src/Database.php';
|
||||||
require 'TMDBMovie.php';
|
require_once './src/TMDBMovie.php';
|
||||||
require 'SSettings.php';
|
require_once './src/SSettings.php';
|
||||||
|
|
||||||
// allow UTF8 characters
|
// allow UTF8 characters
|
||||||
setlocale(LC_ALL, 'en_US.UTF-8');
|
setlocale(LC_ALL, 'en_US.UTF-8');
|
||||||
@ -226,8 +226,7 @@ writeLog("-42"); // terminating characters to stop webui requesting infos
|
|||||||
* @param $video string name including extension
|
* @param $video string name including extension
|
||||||
* @return object all infos as object
|
* @return object all infos as object
|
||||||
*/
|
*/
|
||||||
function _get_video_attributes($video)
|
function _get_video_attributes($video) {
|
||||||
{
|
|
||||||
$command = "mediainfo \"../videos/prn/$video\" --Output=JSON";
|
$command = "mediainfo \"../videos/prn/$video\" --Output=JSON";
|
||||||
$output = shell_exec($command);
|
$output = shell_exec($command);
|
||||||
return json_decode($output);
|
return json_decode($output);
|
||||||
@ -238,8 +237,7 @@ function _get_video_attributes($video)
|
|||||||
*
|
*
|
||||||
* @param string $message message to write
|
* @param string $message message to write
|
||||||
*/
|
*/
|
||||||
function writeLog(string $message)
|
function writeLog(string $message) {
|
||||||
{
|
|
||||||
file_put_contents("/tmp/output.log", $message, FILE_APPEND);
|
file_put_contents("/tmp/output.log", $message, FILE_APPEND);
|
||||||
flush();
|
flush();
|
||||||
}
|
}
|
||||||
@ -249,8 +247,7 @@ function writeLog(string $message)
|
|||||||
* @param string $tagname the name of the tag
|
* @param string $tagname the name of the tag
|
||||||
* @return integer the id of the inserted tag
|
* @return integer the id of the inserted tag
|
||||||
*/
|
*/
|
||||||
function tagExists(string $tagname)
|
function tagExists(string $tagname) {
|
||||||
{
|
|
||||||
global $conn;
|
global $conn;
|
||||||
|
|
||||||
$query = "SELECT * FROM tags WHERE tag_name='$tagname'";
|
$query = "SELECT * FROM tags WHERE tag_name='$tagname'";
|
||||||
|
5
api/settings.php
Normal file
5
api/settings.php
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<?php
|
||||||
|
require_once './src/handlers/Settings.php';
|
||||||
|
|
||||||
|
$sett = new Settings();
|
||||||
|
$sett->handleAction();
|
@ -5,8 +5,7 @@
|
|||||||
*
|
*
|
||||||
* Class with all neccessary stuff for the Database connections.
|
* Class with all neccessary stuff for the Database connections.
|
||||||
*/
|
*/
|
||||||
class Database
|
class Database {
|
||||||
{
|
|
||||||
private static ?Database $instance = null;
|
private static ?Database $instance = null;
|
||||||
private mysqli $conn;
|
private mysqli $conn;
|
||||||
|
|
||||||
@ -16,8 +15,7 @@ class Database
|
|||||||
private string $dbname = "mediacenter";
|
private string $dbname = "mediacenter";
|
||||||
|
|
||||||
// The db connection is established in the private constructor.
|
// The db connection is established in the private constructor.
|
||||||
private function __construct()
|
private function __construct() {
|
||||||
{
|
|
||||||
// Create connection
|
// Create connection
|
||||||
$this->conn = new mysqli($this->servername, $this->username, $this->password, $this->dbname);
|
$this->conn = new mysqli($this->servername, $this->username, $this->password, $this->dbname);
|
||||||
|
|
||||||
@ -32,8 +30,7 @@ class Database
|
|||||||
*
|
*
|
||||||
* @return Database dbobject
|
* @return Database dbobject
|
||||||
*/
|
*/
|
||||||
public static function getInstance()
|
public static function getInstance() {
|
||||||
{
|
|
||||||
if (!self::$instance) {
|
if (!self::$instance) {
|
||||||
self::$instance = new Database();
|
self::$instance = new Database();
|
||||||
}
|
}
|
||||||
@ -46,8 +43,7 @@ class Database
|
|||||||
*
|
*
|
||||||
* @return mysqli mysqli instance
|
* @return mysqli mysqli instance
|
||||||
*/
|
*/
|
||||||
public function getConnection()
|
public function getConnection() {
|
||||||
{
|
|
||||||
return $this->conn;
|
return $this->conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +51,7 @@ class Database
|
|||||||
* get name of current active database
|
* get name of current active database
|
||||||
* @return string name
|
* @return string name
|
||||||
*/
|
*/
|
||||||
public function getDatabaseName(){
|
public function getDatabaseName() {
|
||||||
return $this->dbname;
|
return $this->dbname;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,7 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
class SSettings
|
/**
|
||||||
{
|
* Class SSettings
|
||||||
|
* class handling all Settings used by php scripts
|
||||||
|
*/
|
||||||
|
class SSettings {
|
||||||
private ?Database $database;
|
private ?Database $database;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -11,6 +14,10 @@ class SSettings
|
|||||||
$this->database = Database::getInstance();
|
$this->database = Database::getInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the videopath saved in db
|
||||||
|
* @return string videopath
|
||||||
|
*/
|
||||||
public function getVideoPath() {
|
public function getVideoPath() {
|
||||||
$query = "SELECT video_path from settings";
|
$query = "SELECT video_path from settings";
|
||||||
|
|
||||||
@ -24,14 +31,13 @@ class SSettings
|
|||||||
* check if TMDB is enableds
|
* check if TMDB is enableds
|
||||||
* @return bool isenabled?
|
* @return bool isenabled?
|
||||||
*/
|
*/
|
||||||
public function isTMDBGrabbingEnabled(): bool
|
public function isTMDBGrabbingEnabled(): bool {
|
||||||
{
|
|
||||||
$query = "SELECT TMDB_grabbing from settings";
|
$query = "SELECT TMDB_grabbing from settings";
|
||||||
|
|
||||||
$result = $this->database->getConnection()->query($query);
|
$result = $this->database->getConnection()->query($query);
|
||||||
if(!$result){
|
if (!$result) {
|
||||||
return true; // if undefined in db --> default true
|
return true; // if undefined in db --> default true
|
||||||
}else{
|
} else {
|
||||||
$r = mysqli_fetch_assoc($result);
|
$r = mysqli_fetch_assoc($result);
|
||||||
return $r['TMDB_grabbing'] == '1';
|
return $r['TMDB_grabbing'] == '1';
|
||||||
}
|
}
|
@ -1,10 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
class TMDBMovie
|
/**
|
||||||
{
|
* Class TMDBMovie
|
||||||
|
* class to handle all interactions with the tmdb api
|
||||||
|
*/
|
||||||
|
class TMDBMovie {
|
||||||
|
public $picturebase = "https://image.tmdb.org/t/p/w500";
|
||||||
private $apikey = "9fd90530b11447f5646f8e6fb4733fb4";
|
private $apikey = "9fd90530b11447f5646f8e6fb4733fb4";
|
||||||
private $baseurl = "https://api.themoviedb.org/3/";
|
private $baseurl = "https://api.themoviedb.org/3/";
|
||||||
public $picturebase = "https://image.tmdb.org/t/p/w500";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* search for a specific movie
|
* search for a specific movie
|
||||||
@ -12,8 +15,7 @@ class TMDBMovie
|
|||||||
* @param string $moviename moviename
|
* @param string $moviename moviename
|
||||||
* @return object movie object or null if not found
|
* @return object movie object or null if not found
|
||||||
*/
|
*/
|
||||||
public function searchMovie(string $moviename)
|
public function searchMovie(string $moviename) {
|
||||||
{
|
|
||||||
$reply = json_decode(file_get_contents($this->baseurl . "search/movie?api_key=" . $this->apikey . "&query=" . urlencode($moviename)));
|
$reply = json_decode(file_get_contents($this->baseurl . "search/movie?api_key=" . $this->apikey . "&query=" . urlencode($moviename)));
|
||||||
if ($reply->total_results == 0) {
|
if ($reply->total_results == 0) {
|
||||||
// no results found
|
// no results found
|
||||||
@ -29,8 +31,7 @@ class TMDBMovie
|
|||||||
*
|
*
|
||||||
* @return array of all available genres
|
* @return array of all available genres
|
||||||
*/
|
*/
|
||||||
public function getAllGenres()
|
public function getAllGenres() {
|
||||||
{
|
|
||||||
$reply = json_decode(file_get_contents($this->baseurl . "genre/movie/list?api_key=" . $this->apikey));
|
$reply = json_decode(file_get_contents($this->baseurl . "genre/movie/list?api_key=" . $this->apikey));
|
||||||
return $reply->genres;
|
return $reply->genres;
|
||||||
}
|
}
|
@ -1,14 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once 'Database.php';
|
require_once 'src/Database.php';
|
||||||
|
|
||||||
abstract class RequestBase {
|
abstract class RequestBase {
|
||||||
private array $actions = array();
|
|
||||||
protected mysqli $conn;
|
protected mysqli $conn;
|
||||||
|
private array $actions = array();
|
||||||
/**
|
|
||||||
* add the action handlers in this abstract method
|
|
||||||
*/
|
|
||||||
abstract function initHandlers();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* adds a new action handler to the current api file
|
* adds a new action handler to the current api file
|
||||||
@ -38,4 +33,18 @@ abstract class RequestBase {
|
|||||||
echo('{data:"error"}');
|
echo('{data:"error"}');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send response message and exit script
|
||||||
|
* @param $message string the response message
|
||||||
|
*/
|
||||||
|
function commitMessage($message){
|
||||||
|
echo $message;
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add the action handlers in this abstract method
|
||||||
|
*/
|
||||||
|
abstract function initHandlers();
|
||||||
}
|
}
|
@ -1,8 +1,23 @@
|
|||||||
<?php
|
<?php
|
||||||
require 'RequestBase.php';
|
require_once 'RequestBase.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Settings
|
||||||
|
* Backend for the Settings page
|
||||||
|
*/
|
||||||
class Settings extends RequestBase {
|
class Settings extends RequestBase {
|
||||||
function initHandlers() {
|
function initHandlers() {
|
||||||
|
$this->getFromDB();
|
||||||
|
$this->saveToDB();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* handle settings stuff to load from db
|
||||||
|
*/
|
||||||
|
private function getFromDB(){
|
||||||
|
/**
|
||||||
|
* load currently set settings form db for init of settings page
|
||||||
|
*/
|
||||||
$this->addActionHandler("loadGeneralSettings", function () {
|
$this->addActionHandler("loadGeneralSettings", function () {
|
||||||
$query = "SELECT * from settings";
|
$query = "SELECT * from settings";
|
||||||
|
|
||||||
@ -16,6 +31,30 @@ class Settings extends RequestBase {
|
|||||||
echo json_encode($r);
|
echo json_encode($r);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* load initial data for home page load to check if pwd is set
|
||||||
|
*/
|
||||||
|
$this->addActionHandler("loadInitialData", function () {
|
||||||
|
$query = "SELECT * from settings";
|
||||||
|
|
||||||
|
$result = $this->conn->query($query);
|
||||||
|
|
||||||
|
$r = mysqli_fetch_assoc($result);
|
||||||
|
|
||||||
|
$r['passwordEnabled'] = $r['password'] != "-1";
|
||||||
|
unset($r['password']);
|
||||||
|
$r['DarkMode'] = (bool)($r['DarkMode'] != '0');
|
||||||
|
$this->commitMessage(json_encode($r));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* handle setting stuff to save to db
|
||||||
|
*/
|
||||||
|
private function saveToDB(){
|
||||||
|
/**
|
||||||
|
* save changed settings to db
|
||||||
|
*/
|
||||||
$this->addActionHandler("saveGeneralSettings", function () {
|
$this->addActionHandler("saveGeneralSettings", function () {
|
||||||
$mediacentername = $_POST['mediacentername'];
|
$mediacentername = $_POST['mediacentername'];
|
||||||
$password = $_POST['password'];
|
$password = $_POST['password'];
|
||||||
@ -34,26 +73,10 @@ class Settings extends RequestBase {
|
|||||||
WHERE 1";
|
WHERE 1";
|
||||||
|
|
||||||
if ($this->conn->query($query) === true) {
|
if ($this->conn->query($query) === true) {
|
||||||
echo '{"success": true}';
|
$this->commitMessage('{"success": true}');
|
||||||
} else {
|
} else {
|
||||||
echo '{"success": true}';
|
$this->commitMessage('{"success": true}');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$this->addActionHandler("loadInitialData", function () {
|
|
||||||
$query = "SELECT * from settings";
|
|
||||||
|
|
||||||
$result = $this->conn->query($query);
|
|
||||||
|
|
||||||
$r = mysqli_fetch_assoc($result);
|
|
||||||
|
|
||||||
$r['passwordEnabled'] = $r['password'] != "-1";
|
|
||||||
unset($r['password']);
|
|
||||||
$r['DarkMode'] = (bool)($r['DarkMode'] != '0');
|
|
||||||
echo json_encode($r);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$sett = new Settings();
|
|
||||||
$sett->handleAction();
|
|
66
api/src/handlers/Tags.php
Normal file
66
api/src/handlers/Tags.php
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'RequestBase.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Tags
|
||||||
|
* backend to handle Tag database interactions
|
||||||
|
*/
|
||||||
|
class Tags extends RequestBase {
|
||||||
|
function initHandlers() {
|
||||||
|
$this->addToDB();
|
||||||
|
$this->getFromDB();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getFromDB(){
|
||||||
|
/**
|
||||||
|
* returns all available tags from database
|
||||||
|
*/
|
||||||
|
$this->addActionHandler("getAllTags", function () {
|
||||||
|
$query = "SELECT tag_name,tag_id from tags";
|
||||||
|
$result = $this->conn->query($query);
|
||||||
|
|
||||||
|
$rows = array();
|
||||||
|
while ($r = mysqli_fetch_assoc($result)) {
|
||||||
|
array_push($rows, $r);
|
||||||
|
}
|
||||||
|
$this->commitMessage(json_encode($rows));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private function addToDB(){
|
||||||
|
/**
|
||||||
|
* creates a new tag
|
||||||
|
* query requirements:
|
||||||
|
* * tagname -- name of the new tag
|
||||||
|
*/
|
||||||
|
$this->addActionHandler("createTag", function () {
|
||||||
|
$query = "INSERT INTO tags (tag_name) VALUES ('" . $_POST['tagname'] . "')";
|
||||||
|
|
||||||
|
if ($this->conn->query($query) === TRUE) {
|
||||||
|
$this->commitMessage('{"result":"success"}');
|
||||||
|
} else {
|
||||||
|
$this->commitMessage('{"result":"' . $this->conn->error . '"}');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* adds a new tag to an existing video
|
||||||
|
*
|
||||||
|
* query requirements:
|
||||||
|
* * movieid -- the id of the video to add the tag to
|
||||||
|
* * id -- the tag id which tag to add
|
||||||
|
*/
|
||||||
|
$this->addActionHandler("addTag", function () {
|
||||||
|
$movieid = $_POST['movieid'];
|
||||||
|
$tagid = $_POST['id'];
|
||||||
|
|
||||||
|
$query = "INSERT INTO video_tags(tag_id, video_id) VALUES ('$tagid','$movieid')";
|
||||||
|
|
||||||
|
if ($this->conn->query($query) === TRUE) {
|
||||||
|
$this->commitMessage('{"result":"success"}');
|
||||||
|
} else {
|
||||||
|
$this->commitMessage('{"result":"' . $this->conn->error . '"}');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once 'Database.php';
|
require_once 'src/SSettings.php';
|
||||||
require_once 'SSettings.php';
|
|
||||||
require_once 'RequestBase.php';
|
require_once 'RequestBase.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Video
|
||||||
|
* backend for all interactions with videoloads and receiving of video infos
|
||||||
|
*/
|
||||||
class Video extends RequestBase {
|
class Video extends RequestBase {
|
||||||
private string $videopath;
|
private string $videopath;
|
||||||
|
|
||||||
@ -13,6 +16,15 @@ class Video extends RequestBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function initHandlers() {
|
function initHandlers() {
|
||||||
|
$this->getVideos();
|
||||||
|
$this->loadVideos();
|
||||||
|
$this->addToVideo();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* function handles load of all videos and search for videos
|
||||||
|
*/
|
||||||
|
private function getVideos() {
|
||||||
$this->addActionHandler("getMovies", function () {
|
$this->addActionHandler("getMovies", function () {
|
||||||
$query = "SELECT movie_id,movie_name FROM videos ORDER BY create_date DESC, movie_name";
|
$query = "SELECT movie_id,movie_name FROM videos ORDER BY create_date DESC, movie_name";
|
||||||
if (isset($_POST['tag'])) {
|
if (isset($_POST['tag'])) {
|
||||||
@ -31,7 +43,7 @@ class Video extends RequestBase {
|
|||||||
array_push($rows, $r);
|
array_push($rows, $r);
|
||||||
}
|
}
|
||||||
|
|
||||||
echo(json_encode($rows));
|
$this->commitMessage(json_encode($rows));
|
||||||
});
|
});
|
||||||
|
|
||||||
$this->addActionHandler("getRandomMovies", function () {
|
$this->addActionHandler("getRandomMovies", function () {
|
||||||
@ -59,7 +71,7 @@ class Video extends RequestBase {
|
|||||||
array_push($return->tags, $r);
|
array_push($return->tags, $r);
|
||||||
}
|
}
|
||||||
|
|
||||||
echo(json_encode($return));
|
$this->commitMessage(json_encode($return));
|
||||||
});
|
});
|
||||||
|
|
||||||
$this->addActionHandler("getSearchKeyWord", function () {
|
$this->addActionHandler("getSearchKeyWord", function () {
|
||||||
@ -74,9 +86,14 @@ class Video extends RequestBase {
|
|||||||
array_push($rows, $r);
|
array_push($rows, $r);
|
||||||
}
|
}
|
||||||
|
|
||||||
echo(json_encode($rows));
|
$this->commitMessage(json_encode($rows));
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* function to handle stuff for loading specific videos and startdata
|
||||||
|
*/
|
||||||
|
private function loadVideos() {
|
||||||
$this->addActionHandler("loadVideo", function () {
|
$this->addActionHandler("loadVideo", function () {
|
||||||
$query = "SELECT movie_name,movie_id,movie_url,thumbnail,poster,likes,quality,length FROM videos WHERE movie_id='" . $_POST['movieid'] . "'";
|
$query = "SELECT movie_name,movie_id,movie_url,thumbnail,poster,likes,quality,length FROM videos WHERE movie_id='" . $_POST['movieid'] . "'";
|
||||||
|
|
||||||
@ -110,23 +127,7 @@ class Video extends RequestBase {
|
|||||||
array_push($arr['tags'], $r);
|
array_push($arr['tags'], $r);
|
||||||
}
|
}
|
||||||
|
|
||||||
echo(json_encode($arr));
|
$this->commitMessage(json_encode($arr));
|
||||||
});
|
|
||||||
|
|
||||||
$this->addActionHandler("getDbSize", function () {
|
|
||||||
$dbname = Database::getInstance()->getDatabaseName();
|
|
||||||
|
|
||||||
$query = "SELECT table_schema AS \"Database\",
|
|
||||||
ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS \"Size\"
|
|
||||||
FROM information_schema.TABLES
|
|
||||||
WHERE TABLE_SCHEMA='$dbname'
|
|
||||||
GROUP BY table_schema;";
|
|
||||||
$result = $this->conn->query($query);
|
|
||||||
|
|
||||||
if ($result->num_rows == 1) {
|
|
||||||
$row = $result->fetch_assoc();
|
|
||||||
echo '{"data":"' . $row["Size"] . 'MB"}';
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$this->addActionHandler("readThumbnail", function () {
|
$this->addActionHandler("readThumbnail", function () {
|
||||||
@ -135,38 +136,7 @@ class Video extends RequestBase {
|
|||||||
$result = $this->conn->query($query);
|
$result = $this->conn->query($query);
|
||||||
$row = $result->fetch_assoc();
|
$row = $result->fetch_assoc();
|
||||||
|
|
||||||
echo($row["thumbnail"]);
|
$this->commitMessage($row["thumbnail"]);
|
||||||
});
|
|
||||||
|
|
||||||
$this->addActionHandler("getTags", function () {
|
|
||||||
// todo add this to loadVideo maybe
|
|
||||||
$movieid = $_POST['movieid'];
|
|
||||||
|
|
||||||
$query = "SELECT tag_name FROM video_tags
|
|
||||||
INNER JOIN tags t on video_tags.tag_id = t.tag_id
|
|
||||||
WHERE video_id='$movieid'";
|
|
||||||
|
|
||||||
$result = $this->conn->query($query);
|
|
||||||
|
|
||||||
$rows = array();
|
|
||||||
$rows['tags'] = array();
|
|
||||||
while ($r = mysqli_fetch_assoc($result)) {
|
|
||||||
array_push($rows['tags'], $r['tag_name']);
|
|
||||||
}
|
|
||||||
|
|
||||||
echo(json_encode($rows));
|
|
||||||
});
|
|
||||||
|
|
||||||
$this->addActionHandler("addLike", function () {
|
|
||||||
$movieid = $_POST['movieid'];
|
|
||||||
|
|
||||||
$query = "update videos set likes = likes + 1 where movie_id = '$movieid'";
|
|
||||||
|
|
||||||
if ($this->conn->query($query) === TRUE) {
|
|
||||||
echo('{"result":"success"}');
|
|
||||||
} else {
|
|
||||||
echo('{"result":"' . $this->conn->error . '"}');
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$this->addActionHandler("getStartData", function () {
|
$this->addActionHandler("getStartData", function () {
|
||||||
@ -213,34 +183,24 @@ class Video extends RequestBase {
|
|||||||
$r = mysqli_fetch_assoc($result);
|
$r = mysqli_fetch_assoc($result);
|
||||||
$arr['tags'] = $r['nr'];
|
$arr['tags'] = $r['nr'];
|
||||||
|
|
||||||
echo(json_encode($arr));
|
$this->commitMessage(json_encode($arr));
|
||||||
});
|
});
|
||||||
|
|
||||||
$this->addActionHandler("getAllTags", function () {
|
|
||||||
$query = "SELECT tag_name,tag_id from tags";
|
|
||||||
$result = $this->conn->query($query);
|
|
||||||
|
|
||||||
$rows = array();
|
|
||||||
while ($r = mysqli_fetch_assoc($result)) {
|
|
||||||
array_push($rows, $r);
|
|
||||||
}
|
}
|
||||||
echo(json_encode($rows));
|
|
||||||
});
|
|
||||||
|
|
||||||
$this->addActionHandler("addTag", function () {
|
/**
|
||||||
|
* function to handle api handlers for stuff to add to video or database
|
||||||
|
*/
|
||||||
|
private function addToVideo() {
|
||||||
|
$this->addActionHandler("addLike", function () {
|
||||||
$movieid = $_POST['movieid'];
|
$movieid = $_POST['movieid'];
|
||||||
$tagid = $_POST['id'];
|
|
||||||
|
|
||||||
$query = "INSERT INTO video_tags(tag_id, video_id) VALUES ('$tagid','$movieid')";
|
$query = "update videos set likes = likes + 1 where movie_id = '$movieid'";
|
||||||
|
|
||||||
if ($this->conn->query($query) === TRUE) {
|
if ($this->conn->query($query) === TRUE) {
|
||||||
echo('{"result":"success"}');
|
$this->commitMessage('{"result":"success"}');
|
||||||
} else {
|
} else {
|
||||||
echo('{"result":"' . $this->conn->error . '"}');
|
$this->commitMessage('{"result":"' . $this->conn->error . '"}');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$video = new Video();
|
|
||||||
$video->handleAction();
|
|
5
api/tags.php
Normal file
5
api/tags.php
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<?php
|
||||||
|
include_once './src/handlers/Tags.php';
|
||||||
|
|
||||||
|
$tags = new Tags();
|
||||||
|
$tags->handleAction();
|
5
api/video.php
Normal file
5
api/video.php
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<?php
|
||||||
|
include_once './src/handlers/Video.php';
|
||||||
|
|
||||||
|
$video = new Video();
|
||||||
|
$video->handleAction();
|
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 SettingsPage from "./pages/SettingsPage/SettingsPage";
|
||||||
import CategoryPage from "./pages/CategoryPage/CategoryPage";
|
import CategoryPage from "./pages/CategoryPage/CategoryPage";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main App handles the main tabs and which content to show
|
||||||
|
*/
|
||||||
class App extends React.Component {
|
class App extends React.Component {
|
||||||
newElement = null;
|
newElement = null;
|
||||||
|
|
||||||
@ -31,7 +34,7 @@ class App extends React.Component {
|
|||||||
const updateRequest = new FormData();
|
const updateRequest = new FormData();
|
||||||
updateRequest.append('action', 'loadInitialData');
|
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((response) => response.json()
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
// set theme
|
// 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() {
|
constructViewBinding() {
|
||||||
return {
|
return {
|
||||||
changeRootElement: this.changeRootElement,
|
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() {
|
MainBody() {
|
||||||
let page;
|
let page;
|
||||||
if (this.state.page === "default") {
|
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) {
|
changeRootElement(element) {
|
||||||
this.newElement = element;
|
this.newElement = element;
|
||||||
|
|
||||||
@ -117,6 +131,9 @@ class App extends React.Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return from page to the previous page before a change
|
||||||
|
*/
|
||||||
returnToLastElement() {
|
returnToLastElement() {
|
||||||
this.setState({
|
this.setState({
|
||||||
page: "lastpage"
|
page: "lastpage"
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
.navitem {
|
.navitem {
|
||||||
float: left;
|
|
||||||
margin-left: 20px;
|
|
||||||
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
opacity: 0.6;
|
float: left;
|
||||||
|
|
||||||
font-size: large;
|
font-size: large;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
|
||||||
|
margin-left: 20px;
|
||||||
|
opacity: 0.6;
|
||||||
text-transform: capitalize;
|
text-transform: capitalize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,9 +18,9 @@
|
|||||||
.navitem::after {
|
.navitem::after {
|
||||||
content: '';
|
content: '';
|
||||||
display: block;
|
display: block;
|
||||||
width: 0;
|
|
||||||
height: 2px;
|
height: 2px;
|
||||||
transition: width .3s;
|
transition: width .3s;
|
||||||
|
width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navitem:hover::after {
|
.navitem:hover::after {
|
||||||
@ -33,22 +33,22 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.navcontainer {
|
.navcontainer {
|
||||||
|
border-bottom-width: 2px;
|
||||||
|
border-style: dotted;
|
||||||
|
border-width: 0;
|
||||||
|
|
||||||
|
padding-bottom: 40px;
|
||||||
padding-top: 20px;
|
padding-top: 20px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding-bottom: 40px;
|
|
||||||
|
|
||||||
border-width: 0;
|
|
||||||
border-style: dotted;
|
|
||||||
border-bottom-width: 2px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbrand {
|
.navbrand {
|
||||||
margin-left: 20px;
|
float: left;
|
||||||
margin-right: 20px;
|
|
||||||
font-size: large;
|
font-size: large;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
margin-left: 20px;
|
||||||
|
margin-right: 20px;
|
||||||
text-transform: capitalize;
|
text-transform: capitalize;
|
||||||
float: left;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,23 +1,37 @@
|
|||||||
import darktheme from "./AppDarkTheme.module.css";
|
import darktheme from "./AppDarkTheme.module.css";
|
||||||
import lighttheme from "./AppLightTheme.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 {
|
class StaticInfos {
|
||||||
#darktheme = true;
|
#darktheme = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check if the current theme is the dark theme
|
||||||
|
* @returns {boolean} is dark theme?
|
||||||
|
*/
|
||||||
isDarkTheme() {
|
isDarkTheme() {
|
||||||
return this.#darktheme;
|
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;
|
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;
|
return this.isDarkTheme() ? darktheme : lighttheme;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const GlobalInfos = new StaticInfos();
|
const GlobalInfos = new StaticInfos();
|
||||||
//Object.freeze(StaticInfos);
|
|
||||||
|
|
||||||
export default GlobalInfos;
|
export default GlobalInfos;
|
||||||
|
@ -3,6 +3,9 @@ import Modal from 'react-bootstrap/Modal'
|
|||||||
import Dropdown from "react-bootstrap/Dropdown";
|
import Dropdown from "react-bootstrap/Dropdown";
|
||||||
import DropdownButton from "react-bootstrap/DropdownButton";
|
import DropdownButton from "react-bootstrap/DropdownButton";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* component creates overlay to add a new tag to a video
|
||||||
|
*/
|
||||||
class AddTagPopup extends React.Component {
|
class AddTagPopup extends React.Component {
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
@ -22,7 +25,7 @@ class AddTagPopup extends React.Component {
|
|||||||
const updateRequest = new FormData();
|
const updateRequest = new FormData();
|
||||||
updateRequest.append('action', 'getAllTags');
|
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((response) => response.json())
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
@ -68,13 +71,16 @@ class AddTagPopup extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* store the filled in form to the backend
|
||||||
|
*/
|
||||||
storeselection() {
|
storeselection() {
|
||||||
const updateRequest = new FormData();
|
const updateRequest = new FormData();
|
||||||
updateRequest.append('action', 'addTag');
|
updateRequest.append('action', 'addTag');
|
||||||
updateRequest.append('id', this.state.selection.id);
|
updateRequest.append('id', this.state.selection.id);
|
||||||
updateRequest.append('movieid', this.props.movie_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((response) => response.json()
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
if (result.result !== "success") {
|
if (result.result !== "success") {
|
||||||
|
@ -2,6 +2,9 @@ import React from "react";
|
|||||||
import Modal from 'react-bootstrap/Modal'
|
import Modal from 'react-bootstrap/Modal'
|
||||||
import {Form} from "react-bootstrap";
|
import {Form} from "react-bootstrap";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates modal overlay to define a new Tag
|
||||||
|
*/
|
||||||
class NewTagPopup extends React.Component {
|
class NewTagPopup extends React.Component {
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
@ -45,12 +48,15 @@ class NewTagPopup extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* store the filled in form to the backend
|
||||||
|
*/
|
||||||
storeselection() {
|
storeselection() {
|
||||||
const updateRequest = new FormData();
|
const updateRequest = new FormData();
|
||||||
updateRequest.append('action', 'createTag');
|
updateRequest.append('action', 'createTag');
|
||||||
updateRequest.append('tagname', this.value);
|
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((response) => response.json())
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
if (result.result !== "success") {
|
if (result.result !== "success") {
|
||||||
|
@ -2,14 +2,10 @@ import React from "react";
|
|||||||
import style from "./PageTitle.module.css"
|
import style from "./PageTitle.module.css"
|
||||||
import GlobalInfos from "../../GlobalInfos";
|
import GlobalInfos from "../../GlobalInfos";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component for generating PageTitle with bottom Line
|
||||||
|
*/
|
||||||
class PageTitle extends React.Component {
|
class PageTitle extends React.Component {
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.props = props;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const themeStyle = GlobalInfos.getThemeStyle();
|
const themeStyle = GlobalInfos.getThemeStyle();
|
||||||
return (
|
return (
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.pageheadersubtitle {
|
.pageheadersubtitle {
|
||||||
margin-left: 20px;
|
|
||||||
font-size: 23pt;
|
font-size: 23pt;
|
||||||
|
margin-left: 20px;
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,10 @@ import Player from "../../pages/Player/Player";
|
|||||||
import {Spinner} from "react-bootstrap";
|
import {Spinner} from "react-bootstrap";
|
||||||
import GlobalInfos from "../../GlobalInfos";
|
import GlobalInfos from "../../GlobalInfos";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component for single preview tile
|
||||||
|
* floating side by side
|
||||||
|
*/
|
||||||
class Preview extends React.Component {
|
class Preview extends React.Component {
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
@ -24,7 +28,7 @@ class Preview extends React.Component {
|
|||||||
updateRequest.append('action', 'readThumbnail');
|
updateRequest.append('action', 'readThumbnail');
|
||||||
updateRequest.append('movieid', this.props.movie_id);
|
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((response) => response.text()
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
@ -36,8 +40,8 @@ class Preview extends React.Component {
|
|||||||
render() {
|
render() {
|
||||||
const themeStyle = GlobalInfos.getThemeStyle();
|
const themeStyle = GlobalInfos.getThemeStyle();
|
||||||
return (
|
return (
|
||||||
<div className={style.videopreview + ' ' + themeStyle.secbackground + ' '+ themeStyle.preview} onClick={() => this.itemClick()}>
|
<div className={style.videopreview + ' ' + themeStyle.secbackground + ' ' + themeStyle.preview} onClick={() => this.itemClick()}>
|
||||||
<div className={style.previewtitle + ' '+ themeStyle.lighttextcolor}>{this.state.name}</div>
|
<div className={style.previewtitle + ' ' + themeStyle.lighttextcolor}>{this.state.name}</div>
|
||||||
<div className={style.previewpic}>
|
<div className={style.previewpic}>
|
||||||
{this.state.previewpicture !== null ?
|
{this.state.previewpicture !== null ?
|
||||||
<img className={style.previewimage}
|
<img className={style.previewimage}
|
||||||
@ -53,6 +57,9 @@ class Preview extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* handle the click event of a tile
|
||||||
|
*/
|
||||||
itemClick() {
|
itemClick() {
|
||||||
console.log("item clicked!" + this.state.name);
|
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 {
|
export class TagPreview extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
const themeStyle = GlobalInfos.getThemeStyle();
|
const themeStyle = GlobalInfos.getThemeStyle();
|
||||||
return (
|
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}>
|
<div className={style.tagpreviewtitle + ' ' + themeStyle.lighttextcolor}>
|
||||||
{this.props.name}
|
{this.props.name}
|
||||||
</div>
|
</div>
|
||||||
@ -75,6 +85,9 @@ export class TagPreview extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* handle the click event of a Tag tile
|
||||||
|
*/
|
||||||
itemClick() {
|
itemClick() {
|
||||||
this.props.categorybinding(this.props.name);
|
this.props.categorybinding(this.props.name);
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
.previewtitle {
|
.previewtitle {
|
||||||
height: 20px;
|
|
||||||
text-align: center;
|
|
||||||
font-size: smaller;
|
font-size: smaller;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
|
height: 20px;
|
||||||
max-width: 266px;
|
max-width: 266px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.previewpic {
|
.previewpic {
|
||||||
|
@ -2,24 +2,33 @@ import React from "react";
|
|||||||
import style from "./SideBar.module.css"
|
import style from "./SideBar.module.css"
|
||||||
import GlobalInfos from "../../GlobalInfos";
|
import GlobalInfos from "../../GlobalInfos";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* component for sidebar-info
|
||||||
|
*/
|
||||||
class SideBar extends React.Component {
|
class SideBar extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
const themeStyle = GlobalInfos.getThemeStyle();
|
const themeStyle = GlobalInfos.getThemeStyle();
|
||||||
return (<div className={style.sideinfo + ' '+ themeStyle.secbackground}>
|
return (<div className={style.sideinfo + ' ' + themeStyle.secbackground}>
|
||||||
{this.props.children}
|
{this.props.children}
|
||||||
</div>);
|
</div>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The title of the sidebar
|
||||||
|
*/
|
||||||
export class SideBarTitle extends React.Component {
|
export class SideBarTitle extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
const themeStyle = GlobalInfos.getThemeStyle();
|
const themeStyle = GlobalInfos.getThemeStyle();
|
||||||
return (
|
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 {
|
export class SideBarItem extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
const themeStyle = GlobalInfos.getThemeStyle();
|
const themeStyle = GlobalInfos.getThemeStyle();
|
||||||
|
@ -3,6 +3,9 @@ import React from "react";
|
|||||||
import styles from "./Tag.module.css"
|
import styles from "./Tag.module.css"
|
||||||
import CategoryPage from "../../pages/CategoryPage/CategoryPage";
|
import CategoryPage from "../../pages/CategoryPage/CategoryPage";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Component representing a single Category tag
|
||||||
|
*/
|
||||||
class Tag extends React.Component {
|
class Tag extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
@ -11,9 +14,13 @@ class Tag extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* click handling for a Tag
|
||||||
|
*/
|
||||||
TagClick() {
|
TagClick() {
|
||||||
const tag = this.props.children.toString().toLowerCase();
|
const tag = this.props.children.toString().toLowerCase();
|
||||||
|
|
||||||
|
// call callback functin to switch to category page with specified tag
|
||||||
this.props.viewbinding.changeRootElement(
|
this.props.viewbinding.changeRootElement(
|
||||||
<CategoryPage
|
<CategoryPage
|
||||||
category={tag}
|
category={tag}
|
||||||
|
@ -2,6 +2,10 @@ import React from "react";
|
|||||||
import Preview from "../Preview/Preview";
|
import Preview from "../Preview/Preview";
|
||||||
import style from "./VideoContainer.module.css"
|
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 {
|
class VideoContainer extends React.Component {
|
||||||
// stores current index of loaded elements
|
// stores current index of loaded elements
|
||||||
loadindex = 0;
|
loadindex = 0;
|
||||||
@ -43,9 +47,14 @@ class VideoContainer extends React.Component {
|
|||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
this.setState({});
|
this.setState({});
|
||||||
|
// unbind scroll listener when unmounting component
|
||||||
document.removeEventListener('scroll', this.trackScrolling);
|
document.removeEventListener('scroll', this.trackScrolling);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* load previews to the container
|
||||||
|
* @param nr number of previews to load
|
||||||
|
*/
|
||||||
loadPreviewBlock(nr) {
|
loadPreviewBlock(nr) {
|
||||||
console.log("loadpreviewblock called ...")
|
console.log("loadpreviewblock called ...")
|
||||||
let ret = [];
|
let ret = [];
|
||||||
@ -67,9 +76,11 @@ class VideoContainer extends React.Component {
|
|||||||
this.loadindex += nr;
|
this.loadindex += nr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* scroll event handler -> load new previews if on bottom
|
||||||
|
*/
|
||||||
trackScrolling = () => {
|
trackScrolling = () => {
|
||||||
// comparison if current scroll position is on bottom
|
// comparison if current scroll position is on bottom --> 200 is bottom offset to trigger load
|
||||||
// 200 stands for bottom offset to trigger load
|
|
||||||
if (window.innerHeight + document.documentElement.scrollTop + 200 >= document.documentElement.offsetHeight) {
|
if (window.innerHeight + document.documentElement.scrollTop + 200 >= document.documentElement.offsetHeight) {
|
||||||
this.loadPreviewBlock(8);
|
this.loadPreviewBlock(8);
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,10 @@ import NewTagPopup from "../../elements/NewTagPopup/NewTagPopup";
|
|||||||
import PageTitle, {Line} from "../../elements/PageTitle/PageTitle";
|
import PageTitle, {Line} from "../../elements/PageTitle/PageTitle";
|
||||||
import VideoContainer from "../../elements/VideoContainer/VideoContainer";
|
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 {
|
class CategoryPage extends React.Component {
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageTitle
|
<PageTitle
|
||||||
@ -61,7 +69,14 @@ class CategoryPage extends React.Component {
|
|||||||
this.setState({popupvisible: true})
|
this.setState({popupvisible: true})
|
||||||
}}>Add a new Tag!
|
}}>Add a new Tag!
|
||||||
</button>
|
</button>
|
||||||
</SideBar>
|
</SideBar></>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{this.renderSideBarATitle()}
|
||||||
|
|
||||||
{this.state.selected ?
|
{this.state.selected ?
|
||||||
<>
|
<>
|
||||||
@ -100,10 +115,18 @@ class CategoryPage extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* load a specific tag into a new previewcontainer
|
||||||
|
* @param tagname
|
||||||
|
*/
|
||||||
loadTag = (tagname) => {
|
loadTag = (tagname) => {
|
||||||
this.fetchVideoData(tagname);
|
this.fetchVideoData(tagname);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fetch data for a specific tag from backend
|
||||||
|
* @param tag tagname
|
||||||
|
*/
|
||||||
fetchVideoData(tag) {
|
fetchVideoData(tag) {
|
||||||
console.log(tag);
|
console.log(tag);
|
||||||
const updateRequest = new FormData();
|
const updateRequest = new FormData();
|
||||||
@ -113,7 +136,7 @@ class CategoryPage extends React.Component {
|
|||||||
console.log("fetching data");
|
console.log("fetching data");
|
||||||
|
|
||||||
// fetch all videos available
|
// 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((response) => response.json()
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
this.videodata = result;
|
this.videodata = result;
|
||||||
@ -125,6 +148,9 @@ class CategoryPage extends React.Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* go back to the default category overview
|
||||||
|
*/
|
||||||
loadCategoryPageDefault = () => {
|
loadCategoryPageDefault = () => {
|
||||||
this.setState({selected: null});
|
this.setState({selected: null});
|
||||||
this.loadTags();
|
this.loadTags();
|
||||||
@ -138,7 +164,7 @@ class CategoryPage extends React.Component {
|
|||||||
updateRequest.append('action', 'getAllTags');
|
updateRequest.append('action', 'getAllTags');
|
||||||
|
|
||||||
// fetch all videos available
|
// 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((response) => response.json()
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
this.setState({loadedtags: result});
|
this.setState({loadedtags: result});
|
||||||
|
@ -6,6 +6,9 @@ import VideoContainer from "../../elements/VideoContainer/VideoContainer";
|
|||||||
import style from "./HomePage.module.css"
|
import style from "./HomePage.module.css"
|
||||||
import PageTitle, {Line} from "../../elements/PageTitle/PageTitle";
|
import PageTitle, {Line} from "../../elements/PageTitle/PageTitle";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The home page component showing on the initial pageload
|
||||||
|
*/
|
||||||
class HomePage extends React.Component {
|
class HomePage extends React.Component {
|
||||||
/** keyword variable needed temporary store search keyword */
|
/** keyword variable needed temporary store search keyword */
|
||||||
keyword = "";
|
keyword = "";
|
||||||
@ -47,7 +50,7 @@ class HomePage extends React.Component {
|
|||||||
console.log("fetching data");
|
console.log("fetching data");
|
||||||
|
|
||||||
// fetch all videos available
|
// 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((response) => response.json()
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
@ -71,7 +74,7 @@ class HomePage extends React.Component {
|
|||||||
updateRequest.append('action', 'getStartData');
|
updateRequest.append('action', 'getStartData');
|
||||||
|
|
||||||
// fetch all videos available
|
// 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((response) => response.json()
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
@ -102,7 +105,7 @@ class HomePage extends React.Component {
|
|||||||
updateRequest.append('keyword', keyword);
|
updateRequest.append('keyword', keyword);
|
||||||
|
|
||||||
// fetch all videos available
|
// 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((response) => response.json()
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -8,6 +8,10 @@ import AddTagPopup from "../../elements/AddTagPopup/AddTagPopup";
|
|||||||
import PageTitle, {Line} from "../../elements/PageTitle/PageTitle";
|
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 {
|
class Player extends React.Component {
|
||||||
options = {
|
options = {
|
||||||
controls: [
|
controls: [
|
||||||
@ -59,7 +63,8 @@ class Player extends React.Component {
|
|||||||
{this.state.quality !== 0 ?
|
{this.state.quality !== 0 ?
|
||||||
<SideBarItem><b>{this.state.quality}p</b> Quality!</SideBarItem> : null}
|
<SideBarItem><b>{this.state.quality}p</b> Quality!</SideBarItem> : null}
|
||||||
{this.state.length !== 0 ?
|
{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/>
|
<Line/>
|
||||||
<SideBarTitle>Tags:</SideBarTitle>
|
<SideBarTitle>Tags:</SideBarTitle>
|
||||||
{this.state.tags.map((m) => (
|
{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() {
|
fetchMovieData() {
|
||||||
const updateRequest = new FormData();
|
const updateRequest = new FormData();
|
||||||
updateRequest.append('action', 'loadVideo');
|
updateRequest.append('action', 'loadVideo');
|
||||||
updateRequest.append('movieid', this.props.movie_id);
|
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((response) => response.json())
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
@ -129,13 +137,15 @@ class Player extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Click Listener */
|
/**
|
||||||
|
* click handler for the like btn
|
||||||
|
*/
|
||||||
likebtn() {
|
likebtn() {
|
||||||
const updateRequest = new FormData();
|
const updateRequest = new FormData();
|
||||||
updateRequest.append('action', 'addLike');
|
updateRequest.append('action', 'addLike');
|
||||||
updateRequest.append('movieid', this.props.movie_id);
|
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((response) => response.json()
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
if (result.result === "success") {
|
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() {
|
closebtn() {
|
||||||
this.props.viewbinding.returnToLastElement();
|
this.props.viewbinding.returnToLastElement();
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,8 @@
|
|||||||
float: left;
|
float: left;
|
||||||
margin-left: 20px;
|
margin-left: 20px;
|
||||||
margin-top: 25px;
|
margin-top: 25px;
|
||||||
width: 60%;
|
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
|
width: 60%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.videoactions {
|
.videoactions {
|
||||||
|
@ -5,6 +5,9 @@ import Tag from "../../elements/Tag/Tag";
|
|||||||
import PageTitle from "../../elements/PageTitle/PageTitle";
|
import PageTitle from "../../elements/PageTitle/PageTitle";
|
||||||
import VideoContainer from "../../elements/VideoContainer/VideoContainer";
|
import VideoContainer from "../../elements/VideoContainer/VideoContainer";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Randompage shuffles random viedeopreviews and provides a shuffle btn
|
||||||
|
*/
|
||||||
class RandomPage extends React.Component {
|
class RandomPage extends React.Component {
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
@ -50,17 +53,24 @@ class RandomPage extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* click handler for shuffle btn
|
||||||
|
*/
|
||||||
shuffleclick() {
|
shuffleclick() {
|
||||||
this.loadShuffledvideos(4);
|
this.loadShuffledvideos(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* load random videos from backend
|
||||||
|
* @param nr number of videos to load
|
||||||
|
*/
|
||||||
loadShuffledvideos(nr) {
|
loadShuffledvideos(nr) {
|
||||||
const updateRequest = new FormData();
|
const updateRequest = new FormData();
|
||||||
updateRequest.append('action', 'getRandomMovies');
|
updateRequest.append('action', 'getRandomMovies');
|
||||||
updateRequest.append('number', nr);
|
updateRequest.append('number', nr);
|
||||||
|
|
||||||
// fetch all videos available
|
// 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((response) => response.json()
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
console.log(result);
|
console.log(result);
|
||||||
|
@ -3,6 +3,10 @@ import {Button, Col, Form} from "react-bootstrap";
|
|||||||
import style from "./GeneralSettings.module.css"
|
import style from "./GeneralSettings.module.css"
|
||||||
import GlobalInfos from "../../GlobalInfos";
|
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 {
|
class GeneralSettings extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
@ -19,22 +23,7 @@ class GeneralSettings extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const updateRequest = new FormData();
|
this.loadSettings();
|
||||||
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
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
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() {
|
saveSettings() {
|
||||||
const updateRequest = new FormData();
|
const updateRequest = new FormData();
|
||||||
updateRequest.append('action', 'saveGeneralSettings');
|
updateRequest.append('action', 'saveGeneralSettings');
|
||||||
@ -130,7 +144,7 @@ class GeneralSettings extends React.Component {
|
|||||||
updateRequest.append("tmdbsupport", this.state.tmdbsupport);
|
updateRequest.append("tmdbsupport", this.state.tmdbsupport);
|
||||||
updateRequest.append("darkmodeenabled", GlobalInfos.isDarkTheme());
|
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((response) => response.json()
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import style from "./MovieSettings.module.css"
|
import style from "./MovieSettings.module.css"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component for MovieSettings on Settingspage
|
||||||
|
* handles settings concerning to movies in general
|
||||||
|
*/
|
||||||
class MovieSettings extends React.Component {
|
class MovieSettings extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
@ -36,6 +40,9 @@ class MovieSettings extends React.Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* starts the reindex process of the videos in the specified folder
|
||||||
|
*/
|
||||||
startReindex() {
|
startReindex() {
|
||||||
// clear output text before start
|
// clear output text before start
|
||||||
this.setState({text: []});
|
this.setState({text: []});
|
||||||
@ -60,6 +67,9 @@ class MovieSettings extends React.Component {
|
|||||||
this.myinterval = setInterval(this.updateStatus, 1000);
|
this.myinterval = setInterval(this.updateStatus, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interval function reloads the current status of reindexing from backend
|
||||||
|
*/
|
||||||
updateStatus = () => {
|
updateStatus = () => {
|
||||||
const updateRequest = new FormData();
|
const updateRequest = new FormData();
|
||||||
fetch('/api/extractionData.php', {method: 'POST', body: updateRequest})
|
fetch('/api/extractionData.php', {method: 'POST', body: updateRequest})
|
||||||
|
@ -4,7 +4,10 @@ import GeneralSettings from "./GeneralSettings";
|
|||||||
import style from "./SettingsPage.module.css"
|
import style from "./SettingsPage.module.css"
|
||||||
import GlobalInfos from "../../GlobalInfos";
|
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 {
|
class SettingsPage extends React.Component {
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(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() {
|
getContent() {
|
||||||
switch (this.state.currentpage) {
|
switch (this.state.currentpage) {
|
||||||
case "general":
|
case "general":
|
||||||
|
@ -9,6 +9,11 @@ import Adapter from 'enzyme-adapter-react-16';
|
|||||||
|
|
||||||
configure({adapter: new Adapter()});
|
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) => {
|
global.prepareFetchApi = (response) => {
|
||||||
const mockJsonPromise = Promise.resolve(response);
|
const mockJsonPromise = Promise.resolve(response);
|
||||||
const mockFetchPromise = Promise.resolve({
|
const mockFetchPromise = Promise.resolve({
|
||||||
@ -17,6 +22,10 @@ global.prepareFetchApi = (response) => {
|
|||||||
return (jest.fn().mockImplementation(() => mockFetchPromise));
|
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 = () => {
|
global.prepareFailingFetchApi = () => {
|
||||||
const mockFetchPromise = Promise.reject("myreason");
|
const mockFetchPromise = Promise.reject("myreason");
|
||||||
return (jest.fn().mockImplementation(() => mockFetchPromise));
|
return (jest.fn().mockImplementation(() => mockFetchPromise));
|
||||||
|
Loading…
Reference in New Issue
Block a user