add a new TVPlayer component,
add tv episode path to db
This commit is contained in:
parent
c30c193ce0
commit
f72a3e5fb4
@ -40,4 +40,36 @@ func AddTvshowHandlers() {
|
|||||||
|
|
||||||
return jsonify(episodes)
|
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)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -67,8 +67,8 @@ func insertEpisode(path string, ShowName string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
query := fmt.Sprintf(`
|
query := fmt.Sprintf(`
|
||||||
INSERT INTO tvshow_episodes (name, season, poster, tvshow_id, 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)`, name, season, "", ShowName, episode)
|
VALUES ('%s', %d, '%s', (SELECT tvshow.id FROM tvshow WHERE tvshow.name='%s'), %d, '%s')`, name, season, "", ShowName, episode, path)
|
||||||
err = database.Edit(query)
|
err = database.Edit(query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err.Error())
|
fmt.Println(err.Error())
|
||||||
@ -100,7 +100,8 @@ func insertShowIfNotExisting(show Show, allShows *[]string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// todo load tmdb pic
|
// 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)
|
err := database.Edit(query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err.Error())
|
fmt.Println(err.Error())
|
||||||
|
13
database.sql
13
database.sql
@ -11,8 +11,8 @@ create table if not exists settings
|
|||||||
(
|
(
|
||||||
video_path varchar(255) null,
|
video_path varchar(255) null,
|
||||||
episode_path varchar(255) null,
|
episode_path varchar(255) null,
|
||||||
password varchar(32) null,
|
password varchar(32) default '-1' null,
|
||||||
mediacenter_name varchar(32) null,
|
mediacenter_name varchar(32) default 'OpenMediaCenter' null,
|
||||||
TMDB_grabbing tinyint null,
|
TMDB_grabbing tinyint null,
|
||||||
DarkMode tinyint default 0 null
|
DarkMode tinyint default 0 null
|
||||||
);
|
);
|
||||||
@ -29,7 +29,8 @@ create table if not exists tvshow
|
|||||||
name varchar(100) null,
|
name varchar(100) null,
|
||||||
thumbnail mediumblob null,
|
thumbnail mediumblob null,
|
||||||
id int auto_increment
|
id int auto_increment
|
||||||
primary key
|
primary key,
|
||||||
|
foldername varchar(100) null
|
||||||
);
|
);
|
||||||
|
|
||||||
create table if not exists tvshow_episodes
|
create table if not exists tvshow_episodes
|
||||||
@ -40,6 +41,8 @@ create table if not exists tvshow_episodes
|
|||||||
season int null,
|
season int null,
|
||||||
poster mediumblob null,
|
poster mediumblob null,
|
||||||
tvshow_id int null,
|
tvshow_id int null,
|
||||||
|
episode int null,
|
||||||
|
filename varchar(100) null,
|
||||||
constraint tvshow_episodes_tvshow_id_fk
|
constraint tvshow_episodes_tvshow_id_fk
|
||||||
foreign key (tvshow_id) references tvshow (id)
|
foreign key (tvshow_id) references tvshow (id)
|
||||||
);
|
);
|
||||||
@ -51,11 +54,11 @@ create table if not exists videos
|
|||||||
movie_name varchar(200) null,
|
movie_name varchar(200) null,
|
||||||
movie_url varchar(250) null,
|
movie_url varchar(250) null,
|
||||||
thumbnail mediumblob null,
|
thumbnail mediumblob null,
|
||||||
|
poster mediumblob null,
|
||||||
likes int default 0 null,
|
likes int default 0 null,
|
||||||
create_date datetime default CURRENT_TIMESTAMP null,
|
|
||||||
quality int null,
|
quality int null,
|
||||||
length int null comment 'in seconds',
|
length int null comment 'in seconds',
|
||||||
poster mediumblob null
|
create_date datetime default current_timestamp() null
|
||||||
);
|
);
|
||||||
|
|
||||||
create table if not exists actors_videos
|
create table if not exists actors_videos
|
||||||
|
@ -18,6 +18,7 @@ import ActorPage from './pages/ActorPage/ActorPage';
|
|||||||
import {SettingsTypes} from './types/ApiTypes';
|
import {SettingsTypes} from './types/ApiTypes';
|
||||||
import AuthenticationPage from './pages/AuthenticationPage/AuthenticationPage';
|
import AuthenticationPage from './pages/AuthenticationPage/AuthenticationPage';
|
||||||
import TVShowPage from './pages/TVShowPage/TVShowPage';
|
import TVShowPage from './pages/TVShowPage/TVShowPage';
|
||||||
|
import TVPlayer from './pages/TVShowPage/TVPlayer';
|
||||||
|
|
||||||
interface state {
|
interface state {
|
||||||
password: boolean | null; // null if uninitialized - true if pwd needed false if not needed
|
password: boolean | null; // null if uninitialized - true if pwd needed false if not needed
|
||||||
@ -172,6 +173,9 @@ class App extends React.Component<{}, state> {
|
|||||||
<Route exact path='/player/:id'>
|
<Route exact path='/player/:id'>
|
||||||
<Player />
|
<Player />
|
||||||
</Route>
|
</Route>
|
||||||
|
<Route exact path='/tvplayer/:id'>
|
||||||
|
<TVPlayer />
|
||||||
|
</Route>
|
||||||
<Route exact path='/actors'>
|
<Route exact path='/actors'>
|
||||||
<ActorOverviewPage />
|
<ActorOverviewPage />
|
||||||
</Route>
|
</Route>
|
||||||
|
@ -15,14 +15,14 @@ import ActorTile from '../../elements/ActorTile/ActorTile';
|
|||||||
import {withRouter} from 'react-router-dom';
|
import {withRouter} from 'react-router-dom';
|
||||||
import {APINode, callAPI} from '../../utils/Api';
|
import {APINode, callAPI} from '../../utils/Api';
|
||||||
import {RouteComponentProps} from 'react-router';
|
import {RouteComponentProps} from 'react-router';
|
||||||
import {GeneralSuccess} from '../../types/GeneralTypes';
|
import {DefaultPlyrOptions, GeneralSuccess} from '../../types/GeneralTypes';
|
||||||
import {ActorType, TagType} from '../../types/VideoTypes';
|
import {ActorType, TagType} from '../../types/VideoTypes';
|
||||||
import PlyrJS from 'plyr';
|
import PlyrJS from 'plyr';
|
||||||
import {Button} from '../../elements/GPElements/Button';
|
import {Button} from '../../elements/GPElements/Button';
|
||||||
import {VideoTypes} from '../../types/ApiTypes';
|
import {VideoTypes} from '../../types/ApiTypes';
|
||||||
import GlobalInfos from '../../utils/GlobalInfos';
|
import GlobalInfos from '../../utils/GlobalInfos';
|
||||||
|
|
||||||
interface myprops extends RouteComponentProps<{id: string}> {}
|
interface Props extends RouteComponentProps<{id: string}> {}
|
||||||
|
|
||||||
interface mystate {
|
interface mystate {
|
||||||
sources?: PlyrJS.SourceInfo;
|
sources?: PlyrJS.SourceInfo;
|
||||||
@ -42,25 +42,8 @@ interface mystate {
|
|||||||
* Player page loads when a video is selected to play and handles the video view
|
* Player page loads when a video is selected to play and handles the video view
|
||||||
* and actions such as tag adding and liking
|
* and actions such as tag adding and liking
|
||||||
*/
|
*/
|
||||||
export class Player extends React.Component<myprops, mystate> {
|
export class Player extends React.Component<Props, mystate> {
|
||||||
options: PlyrJS.Options = {
|
constructor(props: Props) {
|
||||||
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) {
|
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
@ -94,7 +77,7 @@ export class Player extends React.Component<myprops, mystate> {
|
|||||||
<div className={style.videowrapper}>
|
<div className={style.videowrapper}>
|
||||||
{/* video component is added here */}
|
{/* video component is added here */}
|
||||||
{this.state.sources ? (
|
{this.state.sources ? (
|
||||||
<Plyr style={plyrstyle} source={this.state.sources} options={this.options} />
|
<Plyr style={plyrstyle} source={this.state.sources} options={DefaultPlyrOptions} />
|
||||||
) : (
|
) : (
|
||||||
<div>not loaded yet</div>
|
<div>not loaded yet</div>
|
||||||
)}
|
)}
|
||||||
|
97
src/pages/TVShowPage/TVPlayer.tsx
Normal file
97
src/pages/TVShowPage/TVPlayer.tsx
Normal file
@ -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<Props, State> {
|
||||||
|
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 <Plyr style={plyrstyle} source={sources} options={DefaultPlyrOptions} />;
|
||||||
|
} else {
|
||||||
|
return <div>not loaded yet</div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<div id='videocontainer'>
|
||||||
|
<PageTitle title='Watch' subtitle='todo' />
|
||||||
|
|
||||||
|
<div className={style.videowrapper}>
|
||||||
|
{/* video component is added here */}
|
||||||
|
{this.assemblePlyrObject()}
|
||||||
|
</div>
|
||||||
|
<button className={style.closebutton} onClick={(): void => this.closebtn()}>
|
||||||
|
Close
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private closebtn(): void {
|
||||||
|
this.props.history.goBack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withRouter(TVPlayer);
|
@ -1,4 +1,5 @@
|
|||||||
import {TagType} from './VideoTypes';
|
import {TagType} from './VideoTypes';
|
||||||
|
import PlyrJS from 'plyr';
|
||||||
|
|
||||||
export interface GeneralSuccess {
|
export interface GeneralSuccess {
|
||||||
result: string;
|
result: string;
|
||||||
@ -14,3 +15,20 @@ export const DefaultTags: TagarrayType = {
|
|||||||
lowq: {TagId: 3, TagName: 'lowquality'},
|
lowq: {TagId: 3, TagName: 'lowquality'},
|
||||||
hd: {TagId: 4, TagName: 'hd'}
|
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
|
||||||
|
]
|
||||||
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user