improved tagging system

new settings page tab
This commit is contained in:
lukas 2020-06-03 12:26:10 +02:00
parent a74cc17e54
commit 0171133d40
11 changed files with 172 additions and 77 deletions

View File

@ -8,7 +8,7 @@ class Database
private $servername = "192.168.0.30"; private $servername = "192.168.0.30";
private $username = "root"; private $username = "root";
private $password = "1qayxsw2"; private $password = "1qayxsw2";
private $dbname = "hub"; private $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()

View File

@ -44,21 +44,21 @@ foreach ($arr as $elem) {
if ($video_attributes['height'] >= 1080) { if ($video_attributes['height'] >= 1080) {
$query = "INSERT INTO video_tags(video_id,tag_id) VALUES ($last_id,2)"; $query = "INSERT INTO video_tags(video_id,tag_id) VALUES ($last_id,2)";
if ($conn->query($query) !== TRUE) { if ($conn->query($query) !== TRUE) {
echo "failed to add tag here.\n"; echo "failed to add default tag here.\n";
} }
} }
if ($video_attributes['height'] >= 720 && $video_attributes['height'] < 1080) { if ($video_attributes['height'] >= 720 && $video_attributes['height'] < 1080) {
$query = "INSERT INTO video_tags(video_id,tag_id) VALUES ($last_id,4)"; $query = "INSERT INTO video_tags(video_id,tag_id) VALUES ($last_id,4)";
if ($conn->query($query) !== TRUE) { if ($conn->query($query) !== TRUE) {
echo "failed to add tag here.\n"; echo "failed to add default tag here.\n";
} }
} }
if ($video_attributes['height'] < 720) { if ($video_attributes['height'] < 720) {
$query = "INSERT INTO video_tags(video_id,tag_id) VALUES ($last_id,3)"; $query = "INSERT INTO video_tags(video_id,tag_id) VALUES ($last_id,3)";
if ($conn->query($query) !== TRUE) { if ($conn->query($query) !== TRUE) {
echo "failed to add tag here.\n"; echo "failed to add default tag here.\n";
} }
} }
$added++; $added++;
@ -125,19 +125,28 @@ function _get_video_attributes($video)
$command = "$ffmpeg -i \"../videos/prn/$video\" -vstats 2>&1"; $command = "$ffmpeg -i \"../videos/prn/$video\" -vstats 2>&1";
$output = shell_exec($command); $output = shell_exec($command);
$codec = "null";
$width = 0;
$height = 0;
$regex_sizes = "/Video: ([^,]*), ([^,]*), ([0-9]{1,4})x([0-9]{1,4})/"; // or : $regex_sizes = "/Video: ([^\r\n]*), ([^,]*), ([0-9]{1,4})x([0-9]{1,4})/"; (code from @1owk3y) $regex_sizes = "/Video: ([^,]*), ([^,]*), ([0-9]{1,4})x([0-9]{1,4})/"; // or : $regex_sizes = "/Video: ([^\r\n]*), ([^,]*), ([0-9]{1,4})x([0-9]{1,4})/"; (code from @1owk3y)
if (preg_match($regex_sizes, $output, $regs)) { if (preg_match($regex_sizes, $output, $regs)) {
$codec = $regs [1] ? $regs [1] : null; $codec = $regs [1] ? $regs [1] : "null";
$width = $regs [3] ? $regs [3] : null; $width = $regs [3] ? $regs [3] : 0;
$height = $regs [4] ? $regs [4] : null; $height = $regs [4] ? $regs [4] : 0;
} }
$hours = 0;
$mins = 0;
$secs = 0;
$ms = 0;
$regex_duration = "/Duration: ([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2}).([0-9]{1,2})/"; $regex_duration = "/Duration: ([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2}).([0-9]{1,2})/";
if (preg_match($regex_duration, $output, $regs)) { if (preg_match($regex_duration, $output, $regs)) {
$hours = $regs [1] ? $regs [1] : null; $hours = $regs [1] ? $regs [1] : 0;
$mins = $regs [2] ? $regs [2] : null; $mins = $regs [2] ? $regs [2] : 0;
$secs = $regs [3] ? $regs [3] : null; $secs = $regs [3] ? $regs [3] : 0;
$ms = $regs [4] ? $regs [4] : null; $ms = $regs [4] ? $regs [4] : 0;
} }
return array('codec' => $codec, return array('codec' => $codec,

View File

@ -3,7 +3,7 @@ require 'Database.php';
$conn = Database::getInstance()->getConnection(); $conn = Database::getInstance()->getConnection();
//$_POST['action'] = "getRandomMovies";$_POST['number'] =6;
if (isset($_POST['action'])) { if (isset($_POST['action'])) {
$action = $_POST['action']; $action = $_POST['action'];
switch ($action) { switch ($action) {
@ -28,14 +28,31 @@ if (isset($_POST['action'])) {
echo(json_encode($rows)); echo(json_encode($rows));
break; break;
case "getRandomMovies": case "getRandomMovies":
$return = new stdClass();
$query = "SELECT movie_id,movie_name FROM videos ORDER BY RAND() LIMIT " . $_POST['number']; $query = "SELECT movie_id,movie_name FROM videos ORDER BY RAND() LIMIT " . $_POST['number'];
$result = $conn->query($query); $result = $conn->query($query);
$rows = array(); $return->rows = array();
// get tags of random videos
$ids = [];
while ($r = mysqli_fetch_assoc($result)) { while ($r = mysqli_fetch_assoc($result)) {
array_push($rows, $r); array_push($return->rows, $r);
array_push($ids,"video_tags.video_id=".$r['movie_id']);
} }
echo(json_encode($rows)); $idstring = implode(" OR ",$ids);
$return->tags = array();
$query = "SELECT t.tag_name FROM video_tags
INNER JOIN tags t on video_tags.tag_id = t.tag_id
WHERE $idstring
GROUP BY t.tag_name";
$result = $conn->query($query);
while ($r = mysqli_fetch_assoc($result)) {
array_push($return->tags, $r);
}
echo(json_encode($return));
break; break;
case "loadVideo": case "loadVideo":
$query = "SELECT movie_name,movie_url,thumbnail,likes,quality,length FROM videos WHERE movie_id='" . $_POST['movieid'] . "'"; $query = "SELECT movie_name,movie_url,thumbnail,likes,quality,length FROM videos WHERE movie_id='" . $_POST['movieid'] . "'";
@ -50,6 +67,18 @@ if (isset($_POST['action'])) {
$arr["likes"] = $row["likes"]; $arr["likes"] = $row["likes"];
$arr["quality"] = $row["quality"]; $arr["quality"] = $row["quality"];
$arr["length"] = $row["length"]; $arr["length"] = $row["length"];
// load tags of this video
$arr['tags'] = Array();
$query = "SELECT t.tag_name FROM video_tags
INNER JOIN tags t on video_tags.tag_id = t.tag_id
WHERE video_tags.video_id=".$_POST['movieid']."
GROUP BY t.tag_name";
$result = $conn->query($query);
while ($r = mysqli_fetch_assoc($result)) {
array_push($arr['tags'], $r);
}
echo(json_encode($arr)); echo(json_encode($arr));
break; break;
@ -77,6 +106,7 @@ if (isset($_POST['action'])) {
break; break;
case "getTags": case "getTags":
// todo add this to loadVideo maybe
$movieid = $_POST['movieid']; $movieid = $_POST['movieid'];
$query = "SELECT tag_name FROM video_tags $query = "SELECT tag_name FROM video_tags

View File

@ -10,10 +10,12 @@ create table if not exists videos
movie_id int auto_increment movie_id int auto_increment
primary key, primary key,
movie_name varchar(200) null, movie_name varchar(200) null,
movie_url varchar(200) null, movie_url varchar(250) null,
thumbnail mediumblob null, thumbnail mediumblob null,
likes int default 0 null, likes int default 0 null,
create_date datetime default CURRENT_TIMESTAMP null create_date datetime default CURRENT_TIMESTAMP null,
quality int null,
length int null comment 'in seconds'
); );
create table if not exists video_tags create table if not exists video_tags

View File

@ -48,19 +48,25 @@ class App extends React.Component {
<li className="nav-item"> <li className="nav-item">
<div className="nav-link" <div className="nav-link"
style={this.state.page === "default" ? {color: "rgba(255,255,255,.75"} : {}} style={this.state.page === "default" ? {color: "rgba(255,255,255,.75"} : {}}
onClick={() => this.loadHomePage()}>Home onClick={() => this.setState({page: "default"})}>Home
</div> </div>
</li> </li>
<li className="nav-item"> <li className="nav-item">
<div className="nav-link" <div className="nav-link"
style={this.state.page === "random" ? {color: "rgba(255,255,255,.75"} : {}} style={this.state.page === "random" ? {color: "rgba(255,255,255,.75"} : {}}
onClick={() => this.loadRandomPage()}>Random Video onClick={() => this.setState({page: "random"})}>Random Video
</div> </div>
</li> </li>
<li className="nav-item"> <li className="nav-item">
<div className="nav-link" <div className="nav-link"
style={this.state.page === "categories" ? {color: "rgba(255,255,255,.75"} : {}} style={this.state.page === "categories" ? {color: "rgba(255,255,255,.75"} : {}}
onClick={() => this.loadCategoriesPage()}>Categories onClick={() => this.setState({page: "categories"})}>Categories
</div>
</li>
<li className="nav-item">
<div className="nav-link"
style={this.state.page === "settings" ? {color: "rgba(255,255,255,.75"} : {}}
onClick={() => this.setState({page: "settings"})}>Settings
</div> </div>
</li> </li>
</ul> </ul>
@ -70,21 +76,6 @@ class App extends React.Component {
); );
} }
loadCategoriesPage() {
console.log("click categories");
this.setState({page: "categories"});
}
loadRandomPage() {
console.log("click random");
this.setState({page: "random"});
}
loadHomePage() {
console.log("click default");
this.setState({page: "default"});
}
showVideo(element) { showVideo(element) {
this.setState({ this.setState({
page: "video" page: "video"

View File

@ -4,6 +4,7 @@ import SideBar from "./SideBar";
import "./css/HomePage.css" import "./css/HomePage.css"
import "./css/DefaultPage.css" import "./css/DefaultPage.css"
import Tag from "./Tag";
class HomePage extends React.Component { class HomePage extends React.Component {
// stores all available movies // stores all available movies
@ -23,7 +24,8 @@ class HomePage extends React.Component {
sdvideonr: null, sdvideonr: null,
tagnr: null tagnr: null
}, },
tag: "all" tag: "All",
selectionnr: null
}; };
} }
@ -34,7 +36,12 @@ class HomePage extends React.Component {
this.fetchStartData(); this.fetchStartData();
} }
// this function clears all preview elements an reloads gravity with tag /**
* fetch available videos for specified tag
* this function clears all preview elements an reloads gravity with tag
*
* @param tag tag to fetch videos
*/
fetchVideoData(tag) { fetchVideoData(tag) {
const updateRequest = new FormData(); const updateRequest = new FormData();
updateRequest.append('action', 'getMovies'); updateRequest.append('action', 'getMovies');
@ -45,7 +52,10 @@ class HomePage extends React.Component {
.then((response) => response.json() .then((response) => response.json()
.then((result) => { .then((result) => {
this.data = result; this.data = result;
this.setState({loadeditems: []}); this.setState({
loadeditems: [],
selectionnr: this.data.length
});
this.loadindex = 0; this.loadindex = 0;
this.loadPreviewBlock(12); this.loadPreviewBlock(12);
})) }))
@ -54,6 +64,9 @@ class HomePage extends React.Component {
}); });
} }
/**
* fetch the necessary data for left info box
*/
fetchStartData() { fetchStartData() {
const updateRequest = new FormData(); const updateRequest = new FormData();
updateRequest.append('action', 'getStartData'); updateRequest.append('action', 'getStartData');
@ -69,7 +82,8 @@ class HomePage extends React.Component {
hdvideonr: result['hd'], hdvideonr: result['hd'],
sdvideonr: result['sd'], sdvideonr: result['sd'],
tagnr: result['tags'] tagnr: result['tags']
}}); }
});
})) }))
.catch(() => { .catch(() => {
console.log("no connection to backend"); console.log("no connection to backend");
@ -86,7 +100,7 @@ class HomePage extends React.Component {
<div> <div>
<div className='pageheader'> <div className='pageheader'>
<span className='pageheadertitle'>Home Page</span> <span className='pageheadertitle'>Home Page</span>
<span className='pageheadersubtitle'>All Videos - {this.state.sideinfo.videonr}</span> <span className='pageheadersubtitle'>{this.state.tag} Videos - {this.state.selectionnr}</span>
<hr/> <hr/>
</div> </div>
<SideBar> <SideBar>
@ -99,10 +113,26 @@ class HomePage extends React.Component {
<div className='sidebarinfo'><b>{this.state.sideinfo.tagnr}</b> different Tags!</div> <div className='sidebarinfo'><b>{this.state.sideinfo.tagnr}</b> different Tags!</div>
<hr/> <hr/>
<div className='sidebartitle'>Default Tags:</div> <div className='sidebartitle'>Default Tags:</div>
<button className='tagbtn' onClick={() => this.fetchVideoData("all")}>All</button> <Tag onClick={() => {
<button className='tagbtn' onClick={() => this.fetchVideoData("fullhd")}>FullHd</button> this.setState({tag: "All"});
<button className='tagbtn' onClick={() => this.fetchVideoData("lowquality")}>LowQuality</button> this.fetchVideoData("all");
<button className='tagbtn' onClick={() => this.fetchVideoData("hd")}>HD</button> }}>All
</Tag>
<Tag onClick={() => {
this.setState({tag: "Full HD"});
this.fetchVideoData("fullhd");
}}>FullHd
</Tag>
<Tag onClick={() => {
this.setState({tag: "Low Quality"});
this.fetchVideoData("lowquality");
}}>LowQuality
</Tag>
<Tag onClick={() => {
this.setState({tag: "HD"});
this.fetchVideoData("hd");
}}>HD
</Tag>
</SideBar> </SideBar>
<div className='maincontent'> <div className='maincontent'>
{this.state.loadeditems.map(elem => ( {this.state.loadeditems.map(elem => (

View File

@ -2,13 +2,21 @@ import React from "react";
import "./css/Player.css" import "./css/Player.css"
import {PlyrComponent} from 'plyr-react'; import {PlyrComponent} from 'plyr-react';
import SideBar from "./SideBar"; import SideBar from "./SideBar";
import Tag from "./Tag";
class Player extends React.Component { class Player extends React.Component {
constructor(props, context) { constructor(props, context) {
super(props, context); super(props, context);
this.state = {}; this.state = {
sources: null,
movie_name: null,
likes: null,
quality: null,
length: null,
tags: []
};
this.props = props; this.props = props;
} }
@ -50,10 +58,9 @@ class Player extends React.Component {
<div className='sidebarinfo'><b>{this.state.length}</b> Minutes of length!</div> <div className='sidebarinfo'><b>{this.state.length}</b> Minutes of length!</div>
<hr/> <hr/>
<div className='sidebartitle'>Tags:</div> <div className='sidebartitle'>Tags:</div>
<button className='tagbtn' onClick={() => this.fetchVideoData("all")}>All</button> {this.state.tags.map((m) => (
<button className='tagbtn' onClick={() => this.fetchVideoData("fullhd")}>FullHd</button> <Tag>{m.tag_name}</Tag>
<button className='tagbtn' onClick={() => this.fetchVideoData("lowquality")}>LowQuality</button> ))}
<button className='tagbtn' onClick={() => this.fetchVideoData("hd")}>HD</button>
</SideBar> </SideBar>
<div className="videowrapper"> <div className="videowrapper">
@ -96,7 +103,8 @@ class Player extends React.Component {
movie_name: result.movie_name, movie_name: result.movie_name,
likes: result.likes, likes: result.likes,
quality: result.quality, quality: result.quality,
length: result.length length: result.length,
tags: result.tags
}); });
}); });
} }

View File

@ -2,13 +2,15 @@ import React from "react";
import Preview from "./Preview"; import Preview from "./Preview";
import "./css/RandomPage.css" import "./css/RandomPage.css"
import SideBar from "./SideBar"; import SideBar from "./SideBar";
import Tag from "./Tag";
class RandomPage extends React.Component { class RandomPage extends React.Component {
constructor(props, context) { constructor(props, context) {
super(props, context); super(props, context);
this.state = { this.state = {
videos: [] videos: [],
tags: []
}; };
} }
@ -26,10 +28,9 @@ class RandomPage extends React.Component {
</div> </div>
<SideBar> <SideBar>
<div className='sidebartitle'>Visible Tags:</div> <div className='sidebartitle'>Visible Tags:</div>
<button className='tagbtn' onClick={() => this.fetchVideoData("all")}>All</button> {this.state.tags.map((m) => (
<button className='tagbtn' onClick={() => this.fetchVideoData("fullhd")}>FullHd</button> <Tag>{m.tag_name}</Tag>
<button className='tagbtn' onClick={() => this.fetchVideoData("lowquality")}>LowQuality</button> ))}
<button className='tagbtn' onClick={() => this.fetchVideoData("hd")}>HD</button>
</SideBar> </SideBar>
<div className='maincontent'> <div className='maincontent'>
@ -61,7 +62,11 @@ class RandomPage extends React.Component {
fetch('/api/videoload.php', {method: 'POST', body: updateRequest}) fetch('/api/videoload.php', {method: 'POST', body: updateRequest})
.then((response) => response.json() .then((response) => response.json()
.then((result) => { .then((result) => {
this.setState({videos: result}); console.log(result);
this.setState({
videos: result.rows,
tags: result.tags
});
})) }))
.catch(() => { .catch(() => {
console.log("no connection to backend"); console.log("no connection to backend");

21
src/Tag.js Normal file
View File

@ -0,0 +1,21 @@
import React from "react";
import "./css/Tag.css"
class Tag extends React.Component {
constructor(props, context) {
super(props, context);
this.props = props;
}
render() {
// todo onclick events correctly
return (
<button className='tagbtn' onClick={this.props.onClick}>{this.props.children}</button>
);
}
}
export default Tag;

View File

@ -9,26 +9,6 @@
border: 2px #3574fe solid; border: 2px #3574fe solid;
} }
.tagbtn {
color: white;
margin: 10px;
background-color: #3574fe;
border: none;
border-radius: 10px;
padding: 5px 15px 5px 15px;
/*font-weight: bold;*/
display: block;
}
.tagbtn:focus {
background-color: #004eff;
outline: none;
}
.tagbtn:hover {
background-color: #004eff;
}
.sidebartitle { .sidebartitle {
font-weight: bold; font-weight: bold;
font-size: larger; font-size: larger;

19
src/css/Tag.css Normal file
View File

@ -0,0 +1,19 @@
.tagbtn {
color: white;
margin: 10px;
background-color: #3574fe;
border: none;
border-radius: 10px;
padding: 5px 15px 5px 15px;
/*font-weight: bold;*/
display: block;
}
.tagbtn:focus {
background-color: #004eff;
outline: none;
}
.tagbtn:hover {
background-color: #004eff;
}