This commit is contained in:
Giampiero Galeazzi
2019-02-17 12:32:33 +01:00
20 changed files with 537 additions and 327 deletions
-1
View File
@@ -26,4 +26,3 @@ yarn-error.log*
.idea/
.vs/
db.json
+1 -1
View File
@@ -1 +1 @@
AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig
'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig'
-44
View File
@@ -1,44 +0,0 @@
{
"videos": [
{
"id": "cu3K1njbYqs",
"timesWatched": 1,
"lastWatched": "2018-12-02T20:43:18.202Z"
},
{
"id": "PoSbnAFvqfA",
"timesWatched": 1,
"lastWatched": "2018-12-02T20:43:24.851Z"
},
{
"id": "rzeLynj1GYM",
"timesWatched": 2,
"lastWatched": "2018-12-02T20:43:45.916Z"
},
{
"id": "0J2QdDbelmY",
"timesWatched": 2,
"lastWatched": "2019-01-09T15:11:09.976Z"
},
{
"id": "unRjK82bDLw",
"timesWatched": 2,
"lastWatched": "2018-12-02T20:49:50.769Z"
},
{
"id": "g2N0TkfrQhY",
"timesWatched": 1,
"lastWatched": "2018-12-02T20:52:07.780Z"
},
{
"id": "EM4vblG6BVQ",
"timesWatched": 1,
"lastWatched": "2018-12-02T20:52:43.282Z"
},
{
"id": "tPwqOWK6EFw",
"timesWatched": 1,
"lastWatched": "2018-12-02T20:53:26.049Z"
}
]
}
+87
View File
@@ -0,0 +1,87 @@
process.env['NODE_ENV'] = 'production';
const express = require('express');
const compression = require('compression')
const bodyParser = require('body-parser');
const low = require('lowdb');
const lodashId = require('lodash-id');
const FileAsync = require('lowdb/adapters/FileAsync');
const app = express(); // app is an instance of express
app.use(compression()); // enables gzip compression
app.use(bodyParser.urlencoded({ extended: false })) // parse application/x-www-form-urlencoded
app.use(bodyParser.json()) // parse application/json
// Create database instance and start server
// const adapter = new FileAsync(__dirname + '/db.json');
low(new FileAsync(__dirname + '/db.json')) // production
.then(db => {
db._.mixin(lodashId);
// DATABASE ROUTES
// ==============
app.post('/test', (req, res) => {
// "reason": {
// "fitali": req.body.reason.toString() === "fvitali" ? 1:0,
// "": req.body.reason.toString() === "" ? 1:0,
// "": req.body.reason.toString() === "" ? 1:0,
// }
// try {
// let test = table.updateById(req.body.id, { })
// }
// catch(e) {
// }
res.send(req.body);
});
// ==============
// GET /globpop
app.get('/globpop', (req, res) => {
req.query.id ? res.send(req.query.id) : res.status(400).send('Bad Request');
});
// OPTIONS /videotrack
app.options('/videotrack', (req, res) => {
res.set({
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Max-Age': 600
})
res.status(200).end();
})
// GET /videotrack
app.get('/videotrack', (req, res) => {
const videos = db.get('videos');
req.query.id ? res.send(videos.getById(req.query.id).value()) : res.send(videos.value())
});
// POST /videotrack
app.post('/videotrack', (req, res) => {
const videos = db.get('videos');
const row = videos.getById(req.body.id);
if (row.value()) {
row
.update('timesWatched', (n) => ++n)
.update('lastWatched', () => new Date().toISOString())
.write()
.then(output => res.send(output))
} else {
let newRow = {
"id": req.body.id.toString(),
"timesWatched": 1,
"lastWatched": new Date().toISOString(),
}
videos.push(newRow).last().write().then(output => res.send(output))
}
});
// Set db default values
return db.defaults({ videos: [] }).write();
})
.then(() => {
app.listen(8000, () => console.log('listen on 8000')); // bind to port 8000 as required from specs
});
+16 -5
View File
@@ -1,5 +1,5 @@
process.env['NODE_ENV'] = 'production';
process.env.APIKEY = 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig';
//'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig' = 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig';
const express = require('express');
const compression = require('compression')
const bodyParser = require('body-parser');
@@ -44,15 +44,26 @@ low(new FileAsync(__dirname + '/db.json')) // production
// ==============
// GET /videotrack/:id?
// GET /globpop
app.get('/globpop', (req, res) => {
req.query.id ? res.send(req.query.id) : res.status(400).send('Bad Request');
});
// GET /videotrack/:id?
app.get('/videotrack/:id?', (req, res) => {
// OPTIONS /videotrack
app.options('/videotrack', (req, res) => {
res.set({
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Max-Age': 600
})
res.status(200).end();
})
// GET /videotrack
app.get('/videotrack', (req, res) => {
const videos = db.get('videos');
req.params.id ? res.send(videos.getById(req.params.id).value()) : res.send(videos.value())
req.query.id ? res.send(videos.getById(req.query.id).value()) : res.send(videos.value())
});
// POST /videotrack
+21 -7
View File
@@ -5879,11 +5879,13 @@
},
"balanced-match": {
"version": "1.0.0",
"bundled": true
"bundled": true,
"optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -5896,15 +5898,18 @@
},
"code-point-at": {
"version": "1.1.0",
"bundled": true
"bundled": true,
"optional": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true
"bundled": true,
"optional": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true
"bundled": true,
"optional": true
},
"core-util-is": {
"version": "1.0.2",
@@ -6007,7 +6012,8 @@
},
"inherits": {
"version": "2.0.3",
"bundled": true
"bundled": true,
"optional": true
},
"ini": {
"version": "1.3.5",
@@ -6017,6 +6023,7 @@
"is-fullwidth-code-point": {
"version": "1.0.0",
"bundled": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@@ -6029,17 +6036,20 @@
"minimatch": {
"version": "3.0.4",
"bundled": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "0.0.8",
"bundled": true
"bundled": true,
"optional": true
},
"minipass": {
"version": "2.2.4",
"bundled": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.1",
"yallist": "^3.0.0"
@@ -6056,6 +6066,7 @@
"mkdirp": {
"version": "0.5.1",
"bundled": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@@ -6128,7 +6139,8 @@
},
"number-is-nan": {
"version": "1.0.1",
"bundled": true
"bundled": true,
"optional": true
},
"object-assign": {
"version": "4.1.1",
@@ -6138,6 +6150,7 @@
"once": {
"version": "1.4.0",
"bundled": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@@ -6243,6 +6256,7 @@
"string-width": {
"version": "1.0.2",
"bundled": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "hazetv-alfatube-1",
"version": "0.1.0",
"version": "0.1.1",
"private": true,
"dependencies": {
"@c0b41/ytclear": "^1.0.0",
+14 -13
View File
@@ -1,6 +1,5 @@
import React from 'react';
import { Route, Switch, withRouter, matchPath } from 'react-router-dom';
import 'bootstrap/dist/css/bootstrap.css';
import { Row, Col, Button, Collapse } from 'react-bootstrap';
import TopBar from './TopBar';
import VideoPlayer from './VideoPlayer';
@@ -45,27 +44,28 @@ static getDerivedStateFromProps(nextProps, prevState) {
render() {
return (
<React.Fragment>
<ReactHeight className="row" onHeightReady={height => { this.setState({ navHeight: height }); }}>
<Row id="top">
<TopBar />
</ReactHeight>
<ReactHeight onHeightReady={height => this.setState({ blackbgHeight: height })} className="row upperSection p-2 px-5" >
</Row>
<Row className="upperSection">
<Col
xs="12"
lg={this.state.isInfoToggled ? { span: 6, offset: 0, order: 2 } : { span: 7, offset: 1, order: 2 }}
className="align-content-center pt-2 p-1 pr-2">
<ReactHeight onHeightReady={height => this.setState({ playerHeight: height })}>
<ReactHeight onHeightReady={height => { this.setState({ playerHeight: height }) }}>
<VideoPlayer videoId={this.state.videoId} />
</ReactHeight>
</Col>
<Col
xs="12"
lg={this.state.isInfoToggled ? { span: 5, order: 1 } : { span: 3, order: 1 }}
className="p-0 p-sm-0"
style={{ 'overflow': "auto", 'max-height': this.state.playerHeight }} >
<div class="d-flex justify-content-center">
className="p-0 p-xs-0"
style={window.innerWidth < 992 ? { 'overflow': "auto", 'display': 'fixed', 'maxHeight': this.state.playerHeight * 1.4 + 'px' } : { 'overflow': "auto", 'maxHeight': `${this.state.playerHeight}px` }}>
{/* true = style for xs ;; false = style for lg */}
<div className="d-flex justify-content-center">
<Button
variant="outline-light"
onClick={() => this.setState({ isInfoToggled: !this.state.isInfoToggled })}
onClick={() => this.setState({ isInfoToggled: !this.state.isInfoToggled, dirtyBg: true })}
className="pt-1 "
aria-controls="infovideo-collapse"
aria-expanded={this.state.isInfoToggled}>
@@ -74,15 +74,16 @@ static getDerivedStateFromProps(nextProps, prevState) {
</div>
<Collapse in={this.state.isInfoToggled}>
<div className="pt-1" id="infovideo-collapse">
<VideoInfo videoId={this.state.videoId} />
<Route render={(props) => <VideoInfo {...props} key={this.state.videoId} videoId={this.state.videoId} />} />
</div>
</Collapse>
</Col>
</ReactHeight>
<Row style={{ "max-height": `calc(98vh - ${this.state.blackbgHeight}px - ${this.state.navHeight}px)` }} className='mt-1 downSection'>
</Row>
<Row style={{ "maxHeight": `calc(98vh - ${this.state.playerHeight}px - 46px)` }} className='mt-1 downSection'>
<Switch>
<Route exact path='/' component={VideoList} />
<Route path={["/video/:id", "/search/:query"]} component={Suggestion} />
<Route path={"/video/:id"} component={Suggestion} />
<Route path={"/search/:query"} component={Suggestion} />
<Route render={() => <div>URL not found</div>} />
</Switch>
</Row>
+24 -95
View File
@@ -1,15 +1,12 @@
import React from 'react';
import Wikipedia from './areainfo/Wikipedia';
import { Tabs, Tab } from 'react-bootstrap';
import {Link, withRouter} from 'react-router-dom';
import { Card, Tabs, Tab } from 'react-bootstrap';
import {Link} from 'react-router-dom';
import axios from 'axios';
import Linkify from "react-linkify";
import Card from "react-bootstrap/lib/Card";
import moment from 'moment';
import momentDurationFormat from 'moment-duration-format'; //eslint-disable-line no-unused-vars
import './css/VideoInfo.scss';
const ytclear = require('@c0b41/ytclear');
class VideoInfo extends React.Component {
@@ -31,88 +28,26 @@ class VideoInfo extends React.Component {
return moment(a, moment.ISO_8601).format('ddd, DD/MM/YYYY hh:mm:ss');
}
isArtistOrTitle(a){
// switch(parseInt(b)){
// case 1:
// break;
// case 2:
// break;
// default:
// break;
// }
axios.all([
axios.get("https://musicbrainz.org/ws/2/work", {
params: {
query: `work:${a[0]} AND artist:${a[1]}`,
//artist: a[1],
fmt: "json",
limit: 1,
inc: "aliases"
}}),
axios.get("https://musicbrainz.org/ws/2/work", {
params: {
query: `work:${a[1]} AND artist:${a[0]}`,
// artist: a[0],
fmt: "json",
limit: 1,
inc: "aliases"
}})
])
.then(axios.spread((response1, response2) => {
console.log(response1.data, response2.data);
axios.all([
axios.get(`https://musicbrainz.org/ws/2/work/${response1.data.works[0].id}`,{
params:{
fmt:'json',
limit:1,
inc: 'aliases'
}
}),
axios.get(`https://musicbrainz.org/ws/2/work/${response2.data.works[0].id}`,{
params:{
fmt:'json',
limit:1,
inc: 'recording-rels'
}
}),
]).then(axios.spread((responseA1,responseA2)=>{
console.log(responseA1.data, responseA2.data);
}))
}),
error => { }
);
}
getInfoComments() {
return axios.all([
axios.get('https://www.googleapis.com/youtube/v3/videos', { //Richiesta per tutte le info sul video
params: {
'part': 'snippet,contentDetails,statistics,topicDetails',
'id': this.state.videoId,
'key': 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig' // process.env.APIKEY in production
'id': this.props.videoId,
'key': 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig' // 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig' in production
}
}), axios.get('https://www.googleapis.com/youtube/v3/commentThreads', { //Richiesta per ottenere i commenti del video
params: {
'part': 'snippet',
'videoId': this.state.videoId,
'videoId': this.props.videoId,
'order': 'relevance',
'key': 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig' // process.env.APIKEY in production
'key': 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig' // 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig' in production
}
})])
.then(axios.spread((videosResponse, commentThreadResponse) => {
this.isArtistOrTitle(ytclear(videosResponse.data.items[0].snippet.title).split('-'));
this.setState({
VideoDetails: videosResponse.data.items[0],
comments: commentThreadResponse.data.items,
others: {
artist: null,
title: videosResponse.data.items[0].snippet.title
},
isLoaded: true
});
}), error => {
@@ -124,19 +59,16 @@ class VideoInfo extends React.Component {
});
}
static getDerivedStateFromProps(nextProps, prevState) {
if(nextProps.videoId !== prevState.videoId)
return { videoId: nextProps.videoId };
return null;
}
// static getDerivedStateFromProps(nextProps, prevState) {
// }
componentDidMount() {
this.getInfoComments();
}
componentDidUpdate(prevProps, prevState, snapshot) {
if(prevState.videoId !== this.state.videoId)
this.getInfoComments();
}
// componentDidUpdate(prevProps, prevState, snapshot) {
// }
// shouldComponentUpdate(nextProps, nextState) {
// }
@@ -157,7 +89,7 @@ class VideoInfo extends React.Component {
} else {
return (
<React.Fragment>
<span class="h5 text-white">{VideoDetails.snippet.title}</span>
<span className="h5 text-white">{VideoDetails.snippet.title}</span>
<Tabs defaultActiveKey="video" id="tabs">
<Tab className="text-white" eventKey="video" title="Video">
<p>
@@ -166,11 +98,9 @@ class VideoInfo extends React.Component {
<b>Channel name: </b>{VideoDetails.snippet.channelTitle}<br />
<b>Description: </b><Linkify>{VideoDetails.snippet.description}</Linkify><br />
<b>Tags: </b>{VideoDetails.snippet.tags ?
VideoDetails.snippet.tags.map(tag => (<Link
to={{
pathname: '/search/' + tag,
}}
> {tag} </Link>)) : ""}
VideoDetails.snippet.tags.map((tag,i) =>
( <span><Link key={i} to={{pathname: '/search/' + tag}}>{tag}</Link>{" "}</span> ))
: ""}
</p>
</Tab>
<Tab className="text-white" eventKey="techinfo" title="Tecnical Informations">
@@ -203,13 +133,16 @@ class VideoInfo extends React.Component {
})}
</Tab>
<Tab className="text-white" eventKey="tweet" title="Tweet">
/* Insert code here */
{/* Insert code here */}
</Tab>
<Tab className="text-white" eventKey="wikipedia" title="Wikipedia">
<Wikipedia
title={this.state.others.title}
artist={this.state.others.artist}
videoId={this.state.videoId}
title={'undefined' !== typeof this.props.location.state ? this.props.location.state.title: undefined}
title2={ytclear(this.state.VideoDetails.snippet.title).split('-')[1]}
artist={'undefined' !== typeof this.props.location.state ? this.props.location.state.artist: undefined}
artist2={ytclear(this.state.VideoDetails.snippet.title).split('-')[0]}
key={this.props.videoId}
videoId={this.props.videoId}
/>
</Tab>
</Tabs>
@@ -217,10 +150,6 @@ class VideoInfo extends React.Component {
);
}
}
}
VideoInfo.propTypes = {
};
export default withRouter(VideoInfo);
export default VideoInfo;
+26 -25
View File
@@ -2,26 +2,28 @@ import React from 'react';
import { Col, ListGroup, Card, CardDeck } from 'react-bootstrap'; // eslint-disable-line no-unused-vars
import axios from 'axios'; // eslint-disable-line no-unused-vars
import { Link } from 'react-router-dom'; // eslint-disable-line no-unused-vars
import './css/VideoList.css';
/*eslint no-console: ["error", { allow: ["warn", "error", "info"] }] */
class VideoList extends React.Component {
constructor(props) {
super(props);
this.state = {
state = {
error: null,
isLoaded: false,
items: [],
headers: null
};
this.getThumbnails = this.getThumbnails.bind(this);
}
componentDidMount() {
localStorage['fixedVideoList'] ?
this.setState({
items: this.shuffleArray(JSON.parse(localStorage.getItem('fixedVideoList'))),
isLoaded: true
}) :
axios.get('http://site1825.tw.cs.unibo.it/video.json').then(
response => {
this.shuffleArray(response.data);
this.getThumbnails(response.data);
this.getThumbnails(response.data)
.then(videoList => localStorage.setItem('fixedVideoList',JSON.stringify(videoList)));
},
// Note: it's important to handle errors here
// instead of a catch() block so that we don't swallow
@@ -33,21 +35,21 @@ class VideoList extends React.Component {
error
});
}
);
)
}
// METODI
getThumbnails(videoItems) {
let idToLookFor = videoItems.map(item => item.videoID);
let finalChunk = (videoItems.length % 50) + 100;
axios
return axios
.all([
// chain 3 parallel get
axios.get('https://www.googleapis.com/youtube/v3/videos', {
params: {
part: 'snippet',
id: idToLookFor.slice(0, 50).toString(),
key: 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig', // process.env.APIKEY in production
key: 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig', // 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig' in production
fields: 'items(id,snippet/thumbnails/medium)'
}
}),
@@ -56,7 +58,7 @@ class VideoList extends React.Component {
params: {
part: 'snippet',
id: idToLookFor.slice(50, 100).toString(),
key: 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig', // process.env.APIKEY in production
key: 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig', // 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig' in production
fields: 'items(id,snippet/thumbnails/medium)'
}
}),
@@ -65,46 +67,45 @@ class VideoList extends React.Component {
params: {
part: 'snippet',
id: idToLookFor.slice(100, finalChunk).toString(),
key: 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig', // process.env.APIKEY in production
key: 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig', // 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig' in production
fields: 'items(id,snippet/thumbnails/medium)'
}
})
])
.then(
axios.spread((res1, res2, res3) => {
let allres = [].concat(
res1.data.items,
res2.data.items,
res3.data.items
);
allres.map(resCurrentValue => {
[...res1.data.items,...res2.data.items,...res3.data.items]
.map(resCurrentValue =>
Object.defineProperty(
videoItems.find(videoItem => {
return videoItem.videoID === resCurrentValue.id;
}),
'thumbnail',
{ value: resCurrentValue.snippet.thumbnails.medium.url }
{ value: resCurrentValue.snippet.thumbnails.medium.url,
enumerable: true }
)
);
});
this.setState({
isLoaded: true,
items: videoItems
});
return new Promise((resolve, reject) => resolve(videoItems))
})
);
)
}
shuffleArray(videoarray) {
for (let i = videoarray.length - 1; i > 0; i--) {
shuffleArray(videoArray) {
for (let i = videoArray.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[videoarray[i], videoarray[j]] = [videoarray[j], videoarray[i]]; // eslint-disable-line no-param-reassign
[videoArray[i], videoArray[j]] = [videoArray[j], videoArray[i]]; // eslint-disable-line no-param-reassign
}
return videoArray
// Durstenfeld shuffle.
// https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm
}
render() {
const { error, isLoaded, items, headers } = this.state;
const { error, isLoaded, items } = this.state;
if (error) {
return (
<React.Fragment>
+2 -2
View File
@@ -86,12 +86,12 @@ class VideoPlayer extends React.Component {
videoIdWatched => {
// post request to local db
axios
.post('http://localhost:8000/videotrack', {
.post('http://site1854.tw.cs.unibo.it/videotrack', {
id: videoIdWatched.toString()
})
.then(
response => console.info(response.data),
error => console.info(error, videoIdWatched.toString())
error => console.error(error, videoIdWatched.toString())
);
// local storage logic for recent reccomender//tmp è il video che devo inserire sulla lista
let tmp = JSON.parse(localStorage.getItem('lastWatched'))
+4 -1
View File
@@ -1,11 +1,12 @@
import React, { Component } from 'react';
import { Row, Col, Button, Collapse } from 'react-bootstrap';
import { Row } from 'react-bootstrap';
import { Switch, Route } from 'react-router';
import Random from '../reccomenders/Random';
import Related from '../reccomenders/Related';
import Search from '../reccomenders/Search';
import fvitali from '../reccomenders/fvitali';
import popGlobaleAssoluta from '../reccomenders/popGlobaleAssoluta';
import Recent from '../reccomenders/Recent';
// and so on..
@@ -40,6 +41,8 @@ class Suggestion extends Component {
<Route path='/search/:query' component={Search} />
<Route path='/video/:id/random' component={Random} />
<Route path='/video/:id/popGlobalAssoluta' component={popGlobaleAssoluta} />
<Route path='/video/:id/recent' component={Recent} />
{/* lasciare questo per ultimo */}
<Route component={Related} />
</Switch>
+45 -39
View File
@@ -17,7 +17,9 @@ class Wikipedia extends Component {
isWikiLoaded: false,
isWDataLoaded: false,
isMBLoaded: false,
isLoaded: false
isLoaded: false,
wikidatakeys: null,
wikipediakeys: null
};
ISO_8601toYYYY(a) {
@@ -50,21 +52,39 @@ class Wikipedia extends Component {
wikipediakeys: Object.keys(wikipediaRes[0].general),
isWikiLoaded: true
}))
else{ console.info('called here')
this.findWikiPage();}
}, error => console.error(error))
// .then(() => {
// console.log(this.state.wikidata)
// .then(() => console.log(this.state.wikipedia));
// });
}
findWikiPage = () => {
let wikiquery = `${'undefined' === typeof this.props.title ? this.props.title2.trim() : this.props.title.trim()} (${'undefined' === typeof this.props.artist ? this.props.artist2.trim() : this.props.artist.trim()} song)`;
console.info(wikiquery)
return wikijs()
.find(wikiquery)
.then(res => {
console.info(res,'a');
return Promise.all([res.fullInfo(), res.summary()]);
}) // find by props.title (props.artist song)
.then(wikipediaRes => this.setState({
wikipedia: {
"desc": wikipediaRes[1],
"info": wikipediaRes[0].general
},
wikipediakeys: Object.keys(wikipediaRes[0].general),
isWikiLoaded: true
}))
}
wrapper() {
const musicbrainzBaseUrl = "https://musicbrainz.org/ws/2"; // more readable
return axios.get(wdk.getReverseClaims('P1651', this.state.props.videoId)) // P1651 is youtube_video_id property
return axios.get(wdk.getReverseClaims('P1651', this.props.videoId)) // P1651 is youtube_video_id property
.then(wikidataP1651Res => {
if (wikidataP1651Res.data.results.bindings.length) { // got a match
this.getWikidataPage(wdk.simplify.sparqlResults(wikidataP1651Res.data))// set in state wikidata
.then(() => {
if (this.state.wikidata.claims.P435) {
if (this.state.wikidata.claims.P435) { // p435 == musicbrainzWorkId
axios.get(`${musicbrainzBaseUrl}/work/${this.state.wikidata.claims.P435[0].mainsnak.datavalue.value}`, { // get musicbrainz info
params: {
'inc': 'artist-rels url-rels',
@@ -105,7 +125,7 @@ class Wikipedia extends Component {
else { //oof
axios.get(`${musicbrainzBaseUrl}/work`, {
params: {
'query': this.state.props.title.trim(),
'query': 'undefined' === typeof this.props.title ? this.props.title2 : this.props.title,
'limit': 1,
'offset': 0,
'fmt': 'json'
@@ -122,41 +142,28 @@ class Wikipedia extends Component {
})
]).then(
axios.spread((wikidataP435Res, musicbrainzWorkRes) => {
this.setState({ musicbrainz: musicbrainzWorkRes.data, isMBLoaded: true });
this.setState({
musicbrainz: musicbrainzWorkRes.data,
isMBLoaded: true
});
if (wikidataP435Res.data.results.bindings.length) // found a match
this.getWikidataPage(wdk.simplify.sparqlResults(wikidataP435Res.data)); // set the result in the state
else if (musicbrainzWorkRes.data.relations.find(currentRel => currentRel.type === "wikidata")) { // found wikidata on music brainz
let a = musicbrainzWorkRes.data.relations.find(currentRel => currentRel.type === "wikidata");
let wikidataUrl = musicbrainzWorkRes.data.relations.find(currentRel => currentRel.type === "wikidata");
let wikidataEntityRegEx = new RegExp("[^/]+$"); // match last part of url https://regex101.com/r/0wCQHY/1
this.getWikidataPage(wikidataEntityRegEx.exec(a.url.resource)) //.then(() => this.setState({ isWikiLoaded: true }));
this.getWikidataPage(wikidataEntityRegEx.exec(wikidataUrl.url.resource)) //.then(() => this.setState({ isWikiLoaded: true }));
}
else { // oof
wikijs().find(this.state.props.title).then(data => console.log('asd', data)) // find by props.title
this.findWikiPage()
}
})
)
})
}
return new Promise((resolve, reject) => resolve('ok'));
});
}
static getDerivedStateFromProps(nextProps, prevState) {
if (prevState.props.videoId !== nextProps.videoId)
return {
props: {
videoId: nextProps.videoId,
artist: nextProps.artist,
title: nextProps.title
},
isWikiLoaded: false,
isWDataLoaded: false,
isMBLoaded: false,
isLoaded: false
};
return null
}
componentDidMount() {
this.wrapper().then(() => this.setState({ isLoaded: true }));
@@ -167,10 +174,9 @@ class Wikipedia extends Component {
// }
componentDidUpdate(prevProps, prevState) {
if (prevState.props.videoId !== this.state.props.videoId)
this.wrapper().then(()=>this.setState({isLoaded: true}));
}
// componentDidUpdate(prevProps, prevState) {
// }
// componentWillUnmount() {
@@ -185,11 +191,11 @@ class Wikipedia extends Component {
return <React.Fragment>Loading...</React.Fragment>;
} else {
return (
<Table striped bordered hover size="sm">
<Table bordered variant="dark" hover size="sm">
<tbody>
{isWikiLoaded &&
this.state.wikipediakeys.map(key => (
<tr>
<tr key={key}>
<td>{key}</td>
<td>{wikipedia.info[key].toLocaleString()}</td>
</tr>
@@ -197,7 +203,7 @@ class Wikipedia extends Component {
}
{isWDataLoaded &&
this.state.wikidatakeys.map(key => (
<tr>
<tr key={key}>
<td>{`${key} - ${wikidata.claims[key][0].mainsnak.datatype}`}</td>
<td>{
typeof wikidata.claims[key][0].mainsnak.datavalue.value === "string" ?
@@ -212,14 +218,14 @@ class Wikipedia extends Component {
))
}
{isMBLoaded &&
musicbrainz.relations.map(relation => {
musicbrainz.relations.map((relation, i) => {
if (relation["target-type"] === "artist")
return (<tr>
return (<tr key={i}>
<td>{relation.type}</td>
<td>{relation.artist.name}</td>
</tr>);
else if (relation["target-type"] === "url")
return (<tr>
return (<tr key={i}>
<td>{relation.type}</td>
<td><a href={relation.url.resource}>{relation.type}</a></td>
</tr>)
+1
View File
@@ -1,5 +1,6 @@
.upperSection{
background-color:#000000;
display: fixed;
}
.downSection{
+3 -1
View File
@@ -1,3 +1,4 @@
import 'bootstrap/dist/css/bootstrap.css';
import 'react-app-polyfill/ie9';
//import '@babel/polyfill';
import React from 'react';
@@ -5,8 +6,9 @@ import ReactDOM from 'react-dom';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import { HashRouter, BrowserRouter } from 'react-router-dom'; // eslint-disable-line
localStorage['lastWatched'] ? function (){}() : localStorage.setItem('lastWatched', JSON.stringify([]))
localStorage['lastId'] ? function (){}() : localStorage.setItem('lastId','0J2QdDbelmY')
ReactDOM.render(<HashRouter><App /></HashRouter>, document.getElementById('root'));
ReactDOM.render(<BrowserRouter><App /></BrowserRouter>, document.getElementById('root'));
registerServiceWorker();
+1 -1
View File
@@ -31,7 +31,7 @@ class RecommenderRandom extends Component{
'type' : 'video', //che contiene tutti i generi di musica
'maxResults': '21',
'pageToken' : pageToken,
'key': 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig' // process.env.APIKEY in production
'key': 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig'
}
}).then(
response => {
+147
View File
@@ -0,0 +1,147 @@
//http://site1825.tw.cs.unibo.it/TW/globpop fvitali
//http://site1825.tw.cs.unibo.it/video.json originale videolist
import React from 'react';
import { Col, ListGroup, Card, CardDeck } from 'react-bootstrap'; // eslint-disable-line no-unused-vars
import axios from 'axios'; // eslint-disable-line no-unused-vars
import { Link } from 'react-router-dom'; // eslint-disable-line no-unused-vars
/*eslint no-console: ["error", { allow: ["warn", "error", "info"] }] */
import moment from "moment";
class Recent extends React.Component {
state = {
error: null,
isLoaded: false,
items: [],
headers: null
};
ISO_8601parse(a) {
return moment(a, moment.ISO_8601).format('ddd, DD/MM/YYYY hh:mm:ss');
}
componentDidMount() {
// axios.get('http://site1825.tw.cs.unibo.it/TW/globpop', {
// 'params':{
// 'id':this.props.id
// }
// }).then(
// response => {
// //this.shuffleArray(response.data);
// console.info ('a',response.data);
this.getThumbnailsNames(JSON.parse(localStorage.getItem('lastWatched')));
// console.info(response.data.recommended);
// // this.setState({
// // isLoaded: true,
// // items:response.data.recommended,
// // });
// },
// // Note: it's important to handle errors here
// // instead of a catch() block so that we don't swallow
// // exceptions from actual bugs in components.
// error => {
// console.error(error);
// this.setState({
// isLoaded: true,
// error
// });
// }
// );
}
// METODI
getThumbnailsNames(recentVideoList) {
let idToLookFor = recentVideoList.map(item => item.id);
axios.get('https://www.googleapis.com/youtube/v3/videos', {
params: {
part: 'snippet',
id: idToLookFor.toString(),
key: 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig',
fields: 'items(id,snippet/thumbnails/medium,snippet/title)'
}
})
.then(
res1 => {
res1.data.items.map(resCurrentValue =>
Object.defineProperties(
recentVideoList.find(videoItem => {
return videoItem.id === resCurrentValue.id;
}),
{
'thumbnail':
{ value: resCurrentValue.snippet.thumbnails.medium.url },
'name':
{ value: resCurrentValue.snippet.title }
})
);
this.setState({
isLoaded: true,
items: recentVideoList
});
})
}
/*shuffleArray(videoarray) {
for (let i = videoarray.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[videoarray[i], videoarray[j]] = [videoarray[j], videoarray[i]]; // eslint-disable-line no-param-reassign
}
// Durstenfeld shuffle.
// https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm
}*/
render() {
const recentVideoList = JSON.parse(localStorage.getItem('lastWatched'))
const { error, isLoaded, items } = this.state;
if (error) {
return (
<React.Fragment>
Error: {error.message} -- Cannot get {error.config.url}
</React.Fragment>
);
} else if (!isLoaded) {
return (
<React.Fragment>
<Col>
<p className="text-center">Loading...</p>
</Col>
</React.Fragment>
);
} else {
return (
<React.Fragment>
{items.map(item => (
<Col md="4">
<Card key={item.id}>
<Link
to={{
pathname: '/video/' + item.id,
}}
>
<Card.Img
src={item.thumbnail}
alt={'Thumbnail of ' + item.name}
/>
<Card.ImgOverlay>
<Card.Title className="bg-dark d-inline text-white">
{item.name}<br />
{item.lastSelected}
</Card.Title>
</Card.ImgOverlay>
</Link>
</Card>
</Col>))}
</React.Fragment>
);
}
}
}
export default Recent;
+1 -1
View File
@@ -33,7 +33,7 @@ class Related extends Component {
'relatedToVideoId' : this.state.videoId,
'type' : 'video',
'maxResults' : '21',
'key': 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig' // process.env.APIKEY in production
'key': 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig'
}
}).then(
response => {
+69 -15
View File
@@ -1,21 +1,45 @@
import React from 'react';
import axios from 'axios';
import { Link } from 'react-router-dom';
import { Card, Col } from 'react-bootstrap';
class Search extends React.Component {
state = {
query: '',
isLoaded: false,
error: null,
res: null
}
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.match.params.query !== prevState.query)
return { query: nextProps.match.params.query };
return null;
}
// static getDerivedStateFromProps(nextProps, prevState) {
// if (nextProps.match.params.query !== prevState.query)
// return { query: nextProps.match.params.query };
// return null;
// }
componentDidMount() {
console.log('called didmo');
if (new RegExp("[0-9A-Za-z_-]{10}[048AEIMQUYcgkosw]").test(this.props.match.params.query.toString()))
axios.get('https://www.googleapis.com/youtube/v3/videos', {
params: {
'part': 'id',
'id': this.props.match.params.query,
'key': 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig',
'field': 'pageInfo/resultsPerPage'
}
}).then(
res => {
res.data.pageInfo.resultsPerPage ?
this.props.history.push('/video/' + this.props.match.params.query) :
this.youtubeSearch()
},
error => {
console.error(error)
}
)
else
this.youtubeSearch();
}
// shouldComponentUpdate(nextProps, nextState) {
@@ -24,22 +48,26 @@ class Search extends React.Component {
componentDidUpdate(prevProps, prevState) {
console.log('called didup');
if(new RegExp("[0-9A-Za-z_-]{10}[048AEIMQUYcgkosw]").test(this.state.query.toString()))
if (prevProps.match.params.query !== this.props.match.params.query)
if (new RegExp("[0-9A-Za-z_-]{10}[048AEIMQUYcgkosw]").test(this.props.match.params.query.toString()))
axios.get('https://www.googleapis.com/youtube/v3/videos', {
params: {
'part': 'id',
'id': this.state.query,
'key': process.env.APIKEY ? process.env.APIKEY : 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig',
'id': this.props.match.params.query,
'key': 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig',
'field': 'pageInfo/resultsPerPage'
}
}).then(
res => {
res.data.pageInfo.resultsPerPage ?
this.props.history.push('/video/' + this.state.query) :
this.props.history.push('/video/' + this.props.match.params.query) :
this.youtubeSearch()
},
error => {
console.error(error)
this.setState({
error
})
}
)
else
@@ -54,18 +82,19 @@ class Search extends React.Component {
return axios.get('https://www.googleapis.com/youtube/v3/search', {
params: {
'part': 'snippet',
'q': this.state.query,
'q': this.props.match.params.query,
'videoEmbeddable': 'true',
'type': 'video',
'maxResults': 30,
'topicId': '/m/04rlf, /m/02jjt',
'key': process.env.APIKEY ? process.env.APIKEY : 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig'
'key': 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig'
}
}).then(
res => {
console.log(res.data);
this.setState({
res: res.data
res: res.data,
isLoaded: true
})
},
error => { console.error(error) }
@@ -73,12 +102,37 @@ class Search extends React.Component {
}
render() {
if (this.state.error) {
return <React.Fragment>Error: {this.state.error.message}</React.Fragment>;
} else if (!this.state.isLoaded) {
return <React.Fragment>Loading...</React.Fragment>;
} else {
return (
<div>
<span>{this.state.query} keyword</span>
</div>
<React.Fragment>
{this.state.res.items.map(item => (<Col key={item.id.videoId} md="4">
<Card>
<Link
to={{
pathname: '/video/' + item.id.videoId,
}}
>
<Card.Img
src={item.snippet.thumbnails.medium.url}
alt={'Thumbnail of ' + item.snippet.title}
/>
<Card.ImgOverlay>
<Card.Title className="bg-dark d-inline text-white">
{item.snippet.title}
</Card.Title>
</Card.ImgOverlay>
</Link>
</Card>
</Col>
))}
</React.Fragment>
);
}
}
}
export default Search;
+5 -6
View File
@@ -64,7 +64,7 @@ class fvitali extends React.Component {
.then(
res1 => {
res1.data.items.map(resCurrentValue => {
res1.data.items.map(resCurrentValue =>
Object.defineProperties(
reccomended.find(videoItem => {
return videoItem.videoID === resCurrentValue.id;
@@ -74,8 +74,8 @@ class fvitali extends React.Component {
{ value: resCurrentValue.snippet.thumbnails.medium.url },
'name':
{value: resCurrentValue.snippet.title}
});
});
})
);
this.setState({
isLoaded: true,
items: reccomended
@@ -95,8 +95,7 @@ class fvitali extends React.Component {
}*/
render() {
const ISO_8601parse = this.ISO_8601parse;
const { error, isLoaded, items, headers } = this.state;
const { error, isLoaded, items } = this.state;
if (error) {
return (
<React.Fragment>
@@ -115,7 +114,7 @@ class fvitali extends React.Component {
return (
<React.Fragment>
{items.map(item=>( <Col md="4">
<Card>
<Card key={item.videoID}>
<Link
to={{
pathname: '/video/' + item.videoID,