From f72a3e5fb4acec27805b9a4f7f92f2c36d597774 Mon Sep 17 00:00:00 2001 From: lukas Date: Thu, 22 Apr 2021 20:31:36 +0200 Subject: [PATCH] add a new TVPlayer component, add tv episode path to db --- apiGo/api/TVShows.go | 32 ++++++++++ apiGo/videoparser/ReIndexTVShows.go | 7 ++- database.sql | 39 ++++++------ src/App.tsx | 4 ++ src/pages/Player/Player.tsx | 27 ++------ src/pages/TVShowPage/TVPlayer.tsx | 97 +++++++++++++++++++++++++++++ src/types/GeneralTypes.ts | 18 ++++++ 7 files changed, 181 insertions(+), 43 deletions(-) create mode 100644 src/pages/TVShowPage/TVPlayer.tsx diff --git a/apiGo/api/TVShows.go b/apiGo/api/TVShows.go index 6c614b5..573459c 100644 --- a/apiGo/api/TVShows.go +++ b/apiGo/api/TVShows.go @@ -40,4 +40,36 @@ func AddTvshowHandlers() { return jsonify(episodes) }) + + var le struct { + ID uint32 + } + AddHandler("loadEpisode", TVShowNode, &le, func() []byte { + query := fmt.Sprintf(` +SELECT tvshow_episodes.name, season, tvshow_id, episode, filename, t.foldername +FROM tvshow_episodes +JOIN tvshow t on t.id = tvshow_episodes.tvshow_id +WHERE tvshow_episodes.id=%d`, le.ID) + row := database.QueryRow(query) + + var ret struct { + Name string + Season uint8 + Episode uint8 + TVShowID uint32 + Path string + } + var filename string + var foldername string + + err := row.Scan(&ret.Name, &ret.Season, &ret.TVShowID, &ret.Episode, &filename, &foldername) + if err != nil { + fmt.Println(err.Error()) + return nil + } + + ret.Path = foldername + "/" + filename + + return jsonify(ret) + }) } diff --git a/apiGo/videoparser/ReIndexTVShows.go b/apiGo/videoparser/ReIndexTVShows.go index 7f5336c..efb70f6 100644 --- a/apiGo/videoparser/ReIndexTVShows.go +++ b/apiGo/videoparser/ReIndexTVShows.go @@ -67,8 +67,8 @@ func insertEpisode(path string, ShowName string) { } query := fmt.Sprintf(` -INSERT INTO tvshow_episodes (name, season, poster, tvshow_id, episode) -VALUES ('%s', %d, '%s', (SELECT tvshow.id FROM tvshow WHERE tvshow.name='%s'), %d)`, name, season, "", ShowName, episode) +INSERT INTO tvshow_episodes (name, season, poster, tvshow_id, episode, filename) +VALUES ('%s', %d, '%s', (SELECT tvshow.id FROM tvshow WHERE tvshow.name='%s'), %d, '%s')`, name, season, "", ShowName, episode, path) err = database.Edit(query) if err != nil { fmt.Println(err.Error()) @@ -100,7 +100,8 @@ func insertShowIfNotExisting(show Show, allShows *[]string) { } // todo load tmdb pic - query := fmt.Sprintf("INSERT INTO tvshow (name, thumbnail) VALUES ('%s', '%s')", show.Name, "") + // currently the foldernamme == name which mustn't necessarily be + query := fmt.Sprintf("INSERT INTO tvshow (name, thumbnail, foldername) VALUES ('%s', '%s', '%s')", show.Name, "", show.Name) err := database.Edit(query) if err != nil { fmt.Println(err.Error()) diff --git a/database.sql b/database.sql index 9b2fd9e..295fe42 100644 --- a/database.sql +++ b/database.sql @@ -9,12 +9,12 @@ create table if not exists actors create table if not exists settings ( - video_path varchar(255) null, - episode_path varchar(255) null, - password varchar(32) null, - mediacenter_name varchar(32) null, - TMDB_grabbing tinyint null, - DarkMode tinyint default 0 null + video_path varchar(255) null, + episode_path varchar(255) null, + password varchar(32) default '-1' null, + mediacenter_name varchar(32) default 'OpenMediaCenter' null, + TMDB_grabbing tinyint null, + DarkMode tinyint default 0 null ); create table if not exists tags @@ -26,10 +26,11 @@ create table if not exists tags create table if not exists tvshow ( - name varchar(100) null, - thumbnail mediumblob null, - id int auto_increment - primary key + name varchar(100) null, + thumbnail mediumblob null, + id int auto_increment + primary key, + foldername varchar(100) null ); create table if not exists tvshow_episodes @@ -40,6 +41,8 @@ create table if not exists tvshow_episodes season int null, poster mediumblob null, tvshow_id int null, + episode int null, + filename varchar(100) null, constraint tvshow_episodes_tvshow_id_fk foreign key (tvshow_id) references tvshow (id) ); @@ -48,14 +51,14 @@ create table if not exists videos ( movie_id int auto_increment primary key, - movie_name varchar(200) null, - movie_url varchar(250) null, - thumbnail mediumblob null, - likes int default 0 null, - create_date datetime default CURRENT_TIMESTAMP null, - quality int null, - length int null comment 'in seconds', - poster mediumblob null + movie_name varchar(200) null, + movie_url varchar(250) null, + thumbnail mediumblob null, + poster mediumblob null, + likes int default 0 null, + quality int null, + length int null comment 'in seconds', + create_date datetime default current_timestamp() null ); create table if not exists actors_videos diff --git a/src/App.tsx b/src/App.tsx index 77f440d..6232cfe 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -18,6 +18,7 @@ import ActorPage from './pages/ActorPage/ActorPage'; import {SettingsTypes} from './types/ApiTypes'; import AuthenticationPage from './pages/AuthenticationPage/AuthenticationPage'; import TVShowPage from './pages/TVShowPage/TVShowPage'; +import TVPlayer from './pages/TVShowPage/TVPlayer'; interface state { password: boolean | null; // null if uninitialized - true if pwd needed false if not needed @@ -172,6 +173,9 @@ class App extends React.Component<{}, state> { + + + diff --git a/src/pages/Player/Player.tsx b/src/pages/Player/Player.tsx index 4711750..342ec9c 100644 --- a/src/pages/Player/Player.tsx +++ b/src/pages/Player/Player.tsx @@ -15,14 +15,14 @@ import ActorTile from '../../elements/ActorTile/ActorTile'; import {withRouter} from 'react-router-dom'; import {APINode, callAPI} from '../../utils/Api'; import {RouteComponentProps} from 'react-router'; -import {GeneralSuccess} from '../../types/GeneralTypes'; +import {DefaultPlyrOptions, GeneralSuccess} from '../../types/GeneralTypes'; import {ActorType, TagType} from '../../types/VideoTypes'; import PlyrJS from 'plyr'; import {Button} from '../../elements/GPElements/Button'; import {VideoTypes} from '../../types/ApiTypes'; import GlobalInfos from '../../utils/GlobalInfos'; -interface myprops extends RouteComponentProps<{id: string}> {} +interface Props extends RouteComponentProps<{id: string}> {} interface mystate { sources?: PlyrJS.SourceInfo; @@ -42,25 +42,8 @@ interface mystate { * Player page loads when a video is selected to play and handles the video view * and actions such as tag adding and liking */ -export class Player extends React.Component { - options: PlyrJS.Options = { - controls: [ - 'play-large', // The large play button in the center - 'play', // Play/pause playback - 'progress', // The progress bar and scrubber for playback and buffering - 'current-time', // The current time of playback - 'duration', // The full duration of the media - 'mute', // Toggle mute - 'volume', // Volume control - 'captions', // Toggle captions - 'settings', // Settings menu - 'airplay', // Airplay (currently Safari only) - 'download', // Show a download button with a link to either the current source or a custom URL you specify in your options - 'fullscreen' // Toggle fullscreen - ] - }; - - constructor(props: myprops) { +export class Player extends React.Component { + constructor(props: Props) { super(props); this.state = { @@ -94,7 +77,7 @@ export class Player extends React.Component {
{/* video component is added here */} {this.state.sources ? ( - + ) : (
not loaded yet
)} diff --git a/src/pages/TVShowPage/TVPlayer.tsx b/src/pages/TVShowPage/TVPlayer.tsx new file mode 100644 index 0000000..40f0fa1 --- /dev/null +++ b/src/pages/TVShowPage/TVPlayer.tsx @@ -0,0 +1,97 @@ +import * as React from 'react'; +import {RouteComponentProps} from 'react-router'; +import {withRouter} from 'react-router-dom'; +import PageTitle from '../../elements/PageTitle/PageTitle'; +import style from '../Player/Player.module.css'; +import {Plyr} from 'plyr-react'; +import plyrstyle from 'plyr-react/dist/plyr.css'; +import {DefaultPlyrOptions} from '../../types/GeneralTypes'; +import {APINode, callAPI} from '../../utils/Api'; +import GlobalInfos from '../../utils/GlobalInfos'; +import PlyrJS from 'plyr'; + +interface Props extends RouteComponentProps<{id: string}> {} + +interface State { + loaded: boolean; +} + +interface EpisodeData { + Name: string; + Season: number; + Episode: number; + TVShowID: number; + Path: string; +} + +class TVPlayer extends React.Component { + state = { + loaded: false + }; + + data: EpisodeData | null = null; + + componentDidMount(): void { + this.loadVideo(); + } + + loadVideo(): void { + callAPI( + APINode.TVShow, + { + action: 'loadEpisode', + ID: parseInt(this.props.match.params.id, 10) + }, + (data: EpisodeData) => { + console.log(data); + this.data = data; + this.setState({loaded: true}); + } + ); + } + + assemblePlyrObject(): JSX.Element { + if (this.state.loaded && this.data !== null) { + const sources: PlyrJS.SourceInfo = { + type: 'video', + sources: [ + { + src: + (process.env.REACT_APP_CUST_BACK_DOMAIN ? process.env.REACT_APP_CUST_BACK_DOMAIN : '') + + GlobalInfos.getTVShowPath() + + this.data.Path, + type: 'video/mp4', + size: 1080 + } + ], + poster: '' + }; + + return ; + } else { + return
not loaded yet
; + } + } + + render(): JSX.Element { + return ( +
+ + +
+ {/* video component is added here */} + {this.assemblePlyrObject()} +
+ +
+ ); + } + + private closebtn(): void { + this.props.history.goBack(); + } +} + +export default withRouter(TVPlayer); diff --git a/src/types/GeneralTypes.ts b/src/types/GeneralTypes.ts index 443ff15..fe62aa3 100644 --- a/src/types/GeneralTypes.ts +++ b/src/types/GeneralTypes.ts @@ -1,4 +1,5 @@ import {TagType} from './VideoTypes'; +import PlyrJS from 'plyr'; export interface GeneralSuccess { result: string; @@ -14,3 +15,20 @@ export const DefaultTags: TagarrayType = { lowq: {TagId: 3, TagName: 'lowquality'}, hd: {TagId: 4, TagName: 'hd'} }; + +export const DefaultPlyrOptions: PlyrJS.Options = { + controls: [ + 'play-large', // The large play button in the center + 'play', // Play/pause playback + 'progress', // The progress bar and scrubber for playback and buffering + 'current-time', // The current time of playback + 'duration', // The full duration of the media + 'mute', // Toggle mute + 'volume', // Volume control + 'captions', // Toggle captions + 'settings', // Settings menu + 'airplay', // Airplay (currently Safari only) + 'download', // Show a download button with a link to either the current source or a custom URL you specify in your options + 'fullscreen' // Toggle fullscreen + ] +};