potete chiudere l'internet PORCODIO

This commit is contained in:
matteo
2019-03-04 17:46:10 +01:00
49 changed files with 1696 additions and 615 deletions
+102 -4
View File
@@ -43,10 +43,62 @@ low(new FileAsync(__dirname + '/db.json')) // production
});
// ==============
// OPTIONS /globpop
app.options('/globpop', (req, res) => {
res.set({
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': ' GET, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Max-Age': 600
})
res.status(200).end();
})
// GET /globpop
app.get('/globpop', (req, res) => {
req.query.id ? res.send(req.query.id) : res.status(400).send('Bad Request');
res.set({
'Access-Control-Allow-Origin': '*'
});
const videos1 = db.get('videos');
let videos = JSON.parse(JSON.stringify(videos1.values()));
if (req.query.id) {
let tmpRes;
let row = videos1.getById(req.query.id);
if (row.value()) {
let tmpA = videos.filter(x => x.id !== req.query.id).map(x => {
return {
"videoID": x.id,
"timesWatched": x.timesWatched,
"prevalentReason": x.reason.sort((a, b) => a.timesWatched - b.timesWatched).reverse()[0].reason,
"lastSelected": x.lastWatched
}
})
tmpRes = {
"site": "site1854.tw.cs.unibo.it",
"recommender": req.query.id.toString(),
"lastWatched": row.value().lastWatched,
"recomended": tmpA
}
}
else {
let tmpA = videos.map(x => {
return {
"videoID": x.id,
"timesWatched": x.timesWatched,
"prevalentReason": x.reason.sort((a, b) => a.timesWatched - b.timesWatched).reverse()[0].reason,
"lastSelected": x.lastWatched
}
})
tmpRes = {
"site": "site1854.tw.cs.unibo.it",
"recommender": req.query.id.toString(),
"lastWatched": "Never Watched",
"recomended": tmpA
}
}
res.send(tmpRes)
} else
res.status(400).send('Bad Request');
});
// OPTIONS /videotrack
@@ -62,8 +114,32 @@ low(new FileAsync(__dirname + '/db.json')) // production
// 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())
res.set({
'Access-Control-Allow-Origin': '*'
});
const videos1 = db.get('videos').values();
let videos = JSON.parse(JSON.stringify(videos1));
console.log(req.query.prevId)
if (req.query.prevId) {
console.log(videos.length)
let tmp = [];
for (let i = 0; i < videos.length; i++) {
console.log(videos[i]);
for (let j = 0; j < videos[i].reason.length; j++) {
console.log(videos[i].reason[j])
if (videos[i].reason[j].prevId === req.query.prevId) {
let tmp2 = {
...videos[i].reason[j],
'id': videos[i].id
}
tmp.push(tmp2);
}
}
}
res.send(tmp)
} else {
res.send(videos)
}
});
// POST /videotrack
@@ -71,19 +147,38 @@ low(new FileAsync(__dirname + '/db.json')) // production
res.set({
'Access-Control-Allow-Origin': '*'
});
let setReason = function (reason = 'Starter', oldArr = [], prevId) {
let j = oldArr.findIndex(el => el.prevId === prevId && el.reason === reason)
if (j >= 0) {
++oldArr[j].timesWatched;
return oldArr
}
else {
let tmp = {
prevId,
reason,
timesWatched: 1
}
oldArr.push(tmp)
return oldArr
}
}
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())
.update('reason', (n) => setReason(req.body.reason, n, req.body.prevId))
.write()
.then(output => res.send(output))
.then(output => res.send(200, output))
} else {
let newRow = {
"id": req.body.id.toString(),
"timesWatched": 1,
"lastWatched": new Date().toISOString(),
"reason": setReason(req.body.reason, [], req.body.prevId)
}
videos.push(newRow).last().write().then(output => res.send(200, output))
}
@@ -94,5 +189,8 @@ low(new FileAsync(__dirname + '/db.json')) // production
})
.then(() => {
app.use(express.static(__dirname + '/build')); // serve static build site
app.get('*', (req, res) => {
res.sendFile(__dirname + '/build/index.html');
});
app.listen(8000, () => console.log('listen on 8000')); // bind to port 8000 as required from specs
});
+8 -22
View File
@@ -1,6 +1,6 @@
{
"name": "hazetv-alfatube-1",
"version": "0.1.0",
"version": "0.1.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -5879,13 +5879,11 @@
},
"balanced-match": {
"version": "1.0.0",
"bundled": true,
"optional": true
"bundled": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -5898,18 +5896,15 @@
},
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"optional": true
"bundled": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
"optional": true
"bundled": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"optional": true
"bundled": true
},
"core-util-is": {
"version": "1.0.2",
@@ -6012,8 +6007,7 @@
},
"inherits": {
"version": "2.0.3",
"bundled": true,
"optional": true
"bundled": true
},
"ini": {
"version": "1.3.5",
@@ -6023,7 +6017,6 @@
"is-fullwidth-code-point": {
"version": "1.0.0",
"bundled": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@@ -6036,20 +6029,17 @@
"minimatch": {
"version": "3.0.4",
"bundled": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "0.0.8",
"bundled": true,
"optional": true
"bundled": true
},
"minipass": {
"version": "2.2.4",
"bundled": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.1",
"yallist": "^3.0.0"
@@ -6066,7 +6056,6 @@
"mkdirp": {
"version": "0.5.1",
"bundled": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@@ -6139,8 +6128,7 @@
},
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
"optional": true
"bundled": true
},
"object-assign": {
"version": "4.1.1",
@@ -6150,7 +6138,6 @@
"once": {
"version": "1.4.0",
"bundled": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@@ -6256,7 +6243,6 @@
"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
@@ -43,7 +43,7 @@
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not ie <= 8",
"not op_mini all"
]
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 88 KiB

+20 -4
View File
@@ -2,7 +2,7 @@ import React, { Component } from 'react'
import { Container, Row, Col, Image } from 'react-bootstrap';
import './css/AboutUs.css';
export default class Home extends Component {
export default class AboutUs extends Component {
render() {
return (
<Container>
@@ -10,17 +10,33 @@ export default class Home extends Component {
<Col xs={12} sm={4} className="person-wrapper">
<Image src="assets/person-1.jpg" roundedCircle className="profile-pic" />
<h3>Matteo Scorzafava</h3>
<p>That's a crooked tree. We'll send him to Washington. These little son of a guns hide in your brush and you just have to push them out.</p>
Wikipedia <br/>
Gestione 15 secondi <br/>
Recommender Search <br/>
Back-end per popolarità <br/>
Recommender similarityArtist <br/>
<p></p>
</Col>
<Col xs={12} sm={4} className="person-wrapper">
<Image src="assets/person-2.jpg" roundedCircle className="profile-pic" />
<h3>Simone Ferrari</h3>
<p>That's a crooked tree. We'll send him to Washington. These little son of a guns hide in your brush and you just have to push them out.</p>
<p>Recommender Random<br/>
Recommender Related<br/>
Recommender Similarity Genere<br/>
Box delle informazioni relative al video
</p>
</Col>
<Col xs={12} sm={4} className="person-wrapper">
<Image src="assets/person-3.jpg" roundedCircle className="profile-pic" />
<h3>Gregorio Giacchetti</h3>
<p>That's a crooked tree. We'll send him to Washington. These little son of a guns hide in your brush and you just have to push them out.</p>
<p>Recommender Recent<br/>
Recommender fvitali<br/>
Gestione della barra dei recommender<br/>
AboutUs <br/>
Recommender similarityArtist
</p>
</Col>
</Row>
</Container>
+11 -11
View File
@@ -34,19 +34,17 @@ class App extends React.Component {
exact: true,
strict: false
});
if (prevState.videoId !== null){
if (idMatch && idMatch.params.id !== prevState.videoId) {
localStorage.setItem('prevId', prevState.videoId)
localStorage.setItem('lastId', idMatch.params.id)
return { videoId: idMatch.params.id };
}
else {
if (idMatch && idMatch.params.id !== prevState.videoId) {
localStorage.setItem('lastId', idMatch.params.id)
return { videoId: idMatch.params.id };
}
return null;
}}}
}
}
render() {
@@ -58,16 +56,18 @@ class App extends React.Component {
<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">
lg={this.state.isInfoToggled ? { span: 8, offset: 0, order: 2 } : { span: 9, offset: 0, order: 2 }}
className="blackBg align-content-center">
<Col xs="12" lg={this.state.isInfoToggled ? { span: 10, offset: 1 } : { span: 10, offset: 1 }}>
<ReactHeight onHeightReady={height => { this.setState({ playerHeight: height }) }}>
<VideoPlayer videoId={this.state.videoId} />
</ReactHeight>
</Col>
</Col>
<Col
xs="12"
lg={this.state.isInfoToggled ? { span: 5, order: 1 } : { span: 3, order: 1 }}
className="p-0 p-xs-0"
lg={this.state.isInfoToggled ? { span: 4, order: 1 } : { span: 3, order: 1 }}
className={this.state.isInfoToggled ? "" : "blackBg"}
style={window.innerWidth < 992 ?
{ 'overflow': "auto", 'display': 'fixed', 'maxHeight': this.state.playerHeight * 1.4 + 'px' } :
{ 'overflow': "auto", 'maxHeight': `${this.state.playerHeight}px` }}>
@@ -89,7 +89,7 @@ class App extends React.Component {
</Collapse>
</Col>
</Row>
<Row style={{ "maxHeight": `calc(98vh - ${this.state.playerHeight}px - 46px)` }} className='mt-1 downSection'>
<Row style={{ "maxHeight": `calc(98vh - ${this.state.playerHeight}px - 40px)` }} className='mt-2 downSection'>
<Switch>
<Route exact path='/' component={VideoList} />
<Route path={"/video/:id"} component={Suggestion} />
+6 -3
View File
@@ -1,5 +1,4 @@
import React, { Component } from 'react';
import { Row } from 'react-bootstrap';
import { Switch, Route } from 'react-router';
import Random from './reccomenders/Random';
import Related from './reccomenders/Related';
@@ -7,7 +6,10 @@ import Search from './reccomenders/Search';
import fvitali from './reccomenders/fvitali';
import popGlobaleAssoluta from './reccomenders/popGlobaleAssoluta';
import Recent from './reccomenders/Recent';
import similarityArtist from './reccomenders/similarityArtist';
import popLocaleAss from './reccomenders/popLocaleAss';
import PopRelLoc from './reccomenders/popRelLoc';
import genreSimilarity from './reccomenders/genreSimilarity';
// and so on..
@@ -36,18 +38,19 @@ class Suggestion extends Component {
render() {
return (
<React.Fragment>
<Row>
<Switch>
<Route path='/video/:id/genreSimilarity' component={genreSimilarity} />
<Route path='/video/:id/vitali' component={fvitali} />
<Route path='/search/:query' component={Search} />
<Route path='/video/:id/random' component={Random} />
<Route path='/video/:id/popGlobalAssoluta' component={popGlobaleAssoluta} />
<Route path='/video/:id/popLocaleAss' component={popLocaleAss} />
<Route path='/video/:id/recent' component={Recent} />
<Route path='/video/:id/similarityArtist' component={similarityArtist} />
<Route path='/video/:id/popRelLoc' component={PopRelLoc} />
{/* lasciare questo per ultimo */}
<Route component={Related} />
</Switch>
</Row>
</React.Fragment>
);
}
+9 -21
View File
@@ -22,15 +22,15 @@ class TopBar extends Component {
}
handleSubmit = event => {
event.preventDefault();
event.target.reset();
// event.target.reset();
this.props.history.push('/search/' + this.state.query);
}
render() {
return (
<React.Fragment>
<Navbar bg="dark" className="py-0 px-1 w-100" expand="md">
<Navbar bg="primary" varian="dark" className="py-0 px-1 w-100" expand="md">
<Navbar.Brand>
<Link to="/">HazeTV</Link>
<Link className="text-light" to="/">HazeTV</Link>
</Navbar.Brand>
<Navbar.Toggle aria-controls="basic-navbar-nav" />
<Navbar.Collapse id="basic-navbar-nav">
@@ -42,42 +42,30 @@ class TopBar extends Component {
<Link to={{ pathname: `/video/${localStorage['lastId']}/related` }} className="text-light nav-link">Related</Link>
{<NavDropdown title="Similarity" id="basic-nav-dropdown" >
<Link to={{ pathname: `/video/${localStorage['lastId']}/...` }} className="text-dark nav-link">
<Link to={{ pathname: `/video/${localStorage['lastId']}/similarityArtist` }} className="text-light nav-link">
Artist
</Link>
<Link to={{ pathname: `/video/${localStorage['lastId']}/...` }} className="text-dark nav-link">
<Link to={{ pathname: `/video/${localStorage['lastId']}/genreSimilarity` }} className="text-light nav-link">
Genre
</Link>
</NavDropdown>}
{<NavDropdown title="Popolarità locale" id="basic-nav-dropdown" >
<Link to={{ pathname: `/video/${localStorage['lastId']}/...` }} className="text-dark nav-link">
<Link to={{ pathname: `/video/${localStorage['lastId']}/popLocaleAss` }} className="text-light nav-link">
Assoluta
</Link>
<Link to={{ pathname: `/video/${localStorage['lastId']}/popRelLoc` }} className="text-dark nav-link">
Relativa
</Link>
</NavDropdown>}
{<NavDropdown title="Popolarità globale" id="basic-nav-dropdown" >
<Link to={{ pathname: `/video/${localStorage['lastId']}/popGlobalAssoluta` }} className="text-dark nav-link">
Assoluta
</Link>
<Link to={{ pathname: `/video/${localStorage['lastId']}/...` }} className="text-dark nav-link">
<Link to={{ pathname: `/video/${localStorage['lastId']}/popRelLoc` }} className="text-light nav-link">
Relativa
</Link>
</NavDropdown>}
<Link to={{ pathname: `/video/${localStorage['lastId']}/progetti` }} className="text-light nav-link">Progetti</Link>
<Link to={{ pathname: `/video/${localStorage['lastId']}/popGlobalAssoluta` }} className="text-light nav-link">popGlobalAssoluta</Link>
</Nav>
<form className="form-inline" onSubmit={this.handleSubmit}>
@@ -87,7 +75,7 @@ class TopBar extends Component {
className="mr-sm-2"
onChange={this.handleChange}
/>
<Button type="submit" variant="outline-success">Search</Button>
<Button type="submit" variant="secondary">Search</Button>
</form>
</Navbar.Collapse>
</Navbar>
+10 -4
View File
@@ -50,11 +50,14 @@ class VideoInfo extends React.Component {
comments: commentThreadResponse.data.items,
isLoaded: true
});
let index = videosResponse.data.items[0].topicDetails.relevantTopicIds.indexOf('/m/04rlf');
videosResponse.data.items[0].topicDetails.relevantTopicIds.splice(index, 1);
localStorage.setItem('lastTopic', videosResponse.data.items[0].topicDetails.relevantTopicIds);
}), error => {
console.error(error);
this.setState({
isLoaded: true,
error
error,
isLoaded: true
});
});
}
@@ -64,14 +67,17 @@ class VideoInfo extends React.Component {
const momentDuration = this.momentDuration;
const ISO_8601parse = this.ISO_8601parse;
if (error) {
let htmlRegEx = /<\/?\w+((\s+\w+(\s*=\s*(?:".*?"|'.*?'|[\^'">\s]+))?)+\s*|\s*)\/?>/gm;
return (
<span className="text-white">
<span>{}</span>
Error: {error.message} -- Cannot get {error.config.url}
Error: {error.message} -- {error.response.data && error.response.data.error.message.replace(htmlRegEx, '')}
</span>
);
} else if (!isLoaded) {
return <span className="text-white">Loading...</span>;
return <div className="text-center">
<div className="lds-ellipsis"><div></div><div></div><div></div><div></div></div>
</div>;
} else {
return (
<React.Fragment>
+35 -10
View File
@@ -1,5 +1,5 @@
import React from 'react';
import { Col, ListGroup, Card, CardDeck } from 'react-bootstrap'; // eslint-disable-line no-unused-vars
import { Col, ListGroup, Card, CardDeck, Media } 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"] }] */
@@ -81,8 +81,10 @@ class VideoList extends React.Component {
return videoItem.videoID === resCurrentValue.id;
}),
'thumbnail',
{ value: resCurrentValue.snippet.thumbnails.medium.url,
enumerable: true }
{
value: resCurrentValue.snippet.thumbnails.medium.url,
enumerable: true
}
)
);
this.setState({
@@ -113,13 +115,9 @@ class VideoList extends React.Component {
</React.Fragment>
);
} else if (!isLoaded) {
return (
<React.Fragment>
<Col>
<p className="text-center">Loading...</p>
</Col>
</React.Fragment>
);
return <Col className="text-center">
<div className="lds-ellipsis"><div></div><div></div><div></div><div></div></div>
</Col>;
} else {
return (
<React.Fragment>
@@ -152,6 +150,33 @@ class VideoList extends React.Component {
</Col>
))}
</React.Fragment>
// <ul className="list-unstyled">{
// items.map(item => (
// <Link
// key={item.videoId}
// as="li" className="media mx-5 my-1 suggItem"
// to={{
// pathname: '/video/' + item.videoID,
// state: {
// artist: item.artist,
// title: item.title
// }
// }}>
// <img
// width={240}
// height={120}
// className="align-self-center mr-3"
// src={item.thumbnail}
// alt={'Thumbnail of ' + item.title}
// />
// <Media.Body>
// <h5>{item.artist} - {item.title}</h5>
// <p>{item.category}</p>
// </Media.Body>
// </Link>
// ))}</ul>
);
}
}
+16 -20
View File
@@ -20,7 +20,7 @@ class VideoPlayer extends React.Component {
}
},
promise1: null,
promise2: null,
promise2: Promise,
outsideReject1: null,
outsideReject2: null
};
@@ -78,7 +78,7 @@ class VideoPlayer extends React.Component {
timerId1 = window.setInterval(() => {
if (event.target.getCurrentTime() > 15)
resolve(event.target.getVideoData().video_id);
}, 1000);
}, 500);
this.setState({ outsideReject1: reject });
})
});
@@ -86,21 +86,23 @@ class VideoPlayer extends React.Component {
.then(
videoIdWatched => {
// post request to local db
let reason = new URLSearchParams(this.props.location.search).get("ref");
axios
.post('http://site1854.tw.cs.unibo.it/videotrack', {
id: videoIdWatched.toString()
id: videoIdWatched.toString(),
reason: reason || undefined,
prevId: localStorage['prevId']
})
.then(
response => console.info(response.data),
error => this.setState({ error })//console.error(error, videoIdWatched.toString())
);
// local storage logic for recent reccomender//tmp è il video che devo inserire sulla lista
// local storage logic for recent reccomender
let tmp = JSON.parse(localStorage.getItem('lastWatched'))
let j = tmp.findIndex(el => el.id.toString() === videoIdWatched.toString())
if (j < 0) {
if (localStorage['prevId']==='1')
{
if (localStorage['prevId'] === '1') {
//per primo video
tmp.push({
'id': videoIdWatched.toString(),
@@ -120,15 +122,6 @@ class VideoPlayer extends React.Component {
}
}
else {
// if (tmp[j].id=='0J2QdDbelmY'){
// tmp[j].timesWatched++;
// tmp[j].lastWatched= new Date();
// let z=tmp[j].prevVideos.findIndex(el=>el.id === localStorage["prevId"].toString())
// if (z<0){
// tmp[j].prevVideos.push({
// 'id': localStorage["prevId"].toString()
// })}
// } else {
//altre volte
tmp[j].timesWatched++;
tmp[j].lastWatched = new Date();
@@ -136,9 +129,9 @@ class VideoPlayer extends React.Component {
if (z < 0) {
tmp[j].prevVideos.push({
'id': localStorage["prevId"].toString()
})}
})
}
//}
}
tmp.sort((a, b) => new Date(b.lastWatched).getTime() - new Date(a.lastWatched).getTime());
@@ -148,21 +141,24 @@ class VideoPlayer extends React.Component {
localStorage.setItem('lastWatched', JSON.stringify(tmp));
//.finally(()=>{})
clearInterval(timerId1);
return new Promise ((resolve,reject) => resolve(videoIdWatched))
},
error => console.error(error)
)
.finally(() => this.setState({ promise1: null, outsideReject1: null }));
.finally((id) => this.setState({ promise1: null, outsideReject1: null }));
break;
case 5:
if (this.state.promise1)
this.state.outsideReject1('Video changed');
break;
default:
break;
}
return new Promise ((resolve,reject) => resolve('ok'))
})
.finally(()=>{this.setState({promise2: null, outsideReject2: null})});
.finally((res) => { this.setState({ promise2: null, outsideReject2: null }) });
}
}
_onStateChange = this._onStateChange.bind(this);
+144 -103
View File
@@ -3,9 +3,10 @@ import { Link } from 'react-router-dom';
import wikijs from 'wikijs';
import wdk from 'wikidata-sdk';
import axios from 'axios';
import { Table } from 'react-bootstrap';
import { Table, Col } from 'react-bootstrap';
import moment from 'moment';
import "./css/Wikipedia.css"
/*eslint no-console: ["error", { allow: ["warn", "error"] }] */
class Wikipedia extends Component {
@@ -40,9 +41,89 @@ class Wikipedia extends Component {
case "P1651": // youtubeid
return (<Link to={{ pathname: `/video/${value}` }}>{`${value}`}</Link>)
case "P2581":
return (<a target="_blank" rel="noopener noreferrer" href={`https://babelnet.org/synset?word=bn:${value}`}>{`${value}`}</a>)
return (<a target="_blank" rel="noopener noreferrer" href={`https://babelnet.org/synset?word=bn:${value}`}>{value}</a>)
case "P1827":
return (<a target="_blank" rel="noopener noreferrer" href={`https://musicbrainz.org/iswc/${value}`}>{value}</a>)
default:
return(`${value}`)
return (`${value}`);
}
}
getMusicBrainzFromWData = (P175, P435=undefined) => { // P175 = artist P435 = workid
const musicbrainzBaseUrl = "https://musicbrainz.org/ws/2"; // more readable
let artist = this.props.artist || this.props.artist2;
let title = this.props.title || this.props.title2;
if (P175.toLowerCase() === artist.trim().toLowerCase()) {
axios
.get(`https://musicbrainz.org/ws/2/recording`, {
params: {
'query': `${title.trim()} AND artistname:${artist.trim()}`, //AND release:${P361}
'limit': 1,
'fmt': 'json'
}
})
.then(resP175EqArtist => {
axios
.get(`${musicbrainzBaseUrl}/recording/${resP175EqArtist.data.recordings[0].id}`, {
params: {
'inc': 'work-rels+artists+releases',
'fmt': 'json'
}
})
.then(resRecordingQuery => {
let musicbrainzWorkId = resRecordingQuery.data.relations.map(x => x['target-type'] === 'work' ? x.work.id.toString() : "") || P435.toString();
axios.get(`${musicbrainzBaseUrl}/work/${musicbrainzWorkId}`, {
params:{
'inc': 'artist-rels url-rels',
'limit': 1,
'offset': 0,
'fmt': 'json'
}
})
.then(musicbrainzWorkRes => {
this.setState({ musicbrainz: musicbrainzWorkRes.data, isMBLoaded: true })
},
error => console.error(error))
}, err => { console.error(err) })
}
, err => console.error(err))
}
else if (P175.toLowerCase() === title.trim().toLowerCase()) { // video title was title - artist
axios
.get(`https://musicbrainz.org/ws/2/recording`, {
params: {
'query': `"${artist.trim()}" AND artistname:"${title.trim()}"`, //AND release:${P361}
'limit': 1,
'fmt': 'json'
}
})
.then(resP175EqTitle => {
axios
.get(`${musicbrainzBaseUrl}/recording/${resP175EqTitle.data.recordings[0].id}`, {
params: {
'inc': 'work-rels+artists+releases',
'fmt': 'json'
}
})
.then(resRecordingQuery => {
let musicbrainzWorkId = resRecordingQuery.data.relations.map(x => x['target-type'] === 'work' ? x.work.id.toString() : "") || P435.toString();
axios.get(`${musicbrainzBaseUrl}/work/${musicbrainzWorkId}`, {
params:{
'inc': 'artist-rels url-rels',
'limit': 1,
'offset': 0,
'fmt': 'json'
}
})
.then(musicbrainzWorkRes => {
this.setState({ musicbrainz: musicbrainzWorkRes.data, isMBLoaded: true })
},
error => console.error(error))
}, err => { console.error(err) })
}
, err => console.error(err))
}
}
@@ -60,44 +141,53 @@ class Wikipedia extends Component {
.map(x => wikidatatmp.claims[x][0].mainsnak.datavalue.value.id)
.filter(x => typeof x === 'string'), 'en'))
])
.then(axios.spread((resKey, resQ) => {
.then(
axios.spread((resKey, resQ) => {
this.setState({
wikidatakeys: Object.entries(resKey.data.entities),
wikidataQ: resQ.data.entities,
isWDataLoaded: true
})
try{
this.getMusicBrainzFromWData(
resQ.data.entities[wikidatatmp.claims.P175[0].mainsnak.datavalue.value.id].labels.en.value,
wikidatatmp.claims.P435[0].mainsnak.datavalue.value
);
}
catch(e){
console.error(e)
this.getMusicBrainzFromWData(
resQ.data.entities[wikidatatmp.claims.P175[0].mainsnak.datavalue.value.id].labels.en.value
);
}
}))
if (wikidatatmp.sitelinks.enwiki)
wikijs()
.page(wikidatatmp.sitelinks.enwiki.title)
.then(page => Promise.all([page.fullInfo(), page.summary()]))
.then(page => Promise.all([page.fullInfo()]))
.then(wikipediaRes => this.setState({
wikipedia: {
"desc": wikipediaRes[1],
// "desc": wikipediaRes[1],
"info": wikipediaRes[0].general
},
wikipediakeys: Object.keys(wikipediaRes[0].general),
isWikiLoaded: true
}))
else {
console.info('called here')
this.findWikiPage();
}
}, error => console.error(error))
}
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)
let wikiquery = `${'undefined' === typeof this.props.title ? ('undefined' === typeof this.props.title2 ? this.props.artist2 : this.props.title2) : this.props.title.trim()} ${'undefined' === typeof this.props.title && 'undefined' === typeof this.props.title2 ? "" : `(${'undefined' === typeof this.props.artist ? this.props.artist2.trim() : this.props.artist.trim()} song)`}`;
return wikijs()
.find(wikiquery)
.then(res => {
console.info(res, 'a');
return Promise.all([res.fullInfo(), res.summary()]);
return Promise.all([res.fullInfo()]);
}) // 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),
@@ -106,99 +196,50 @@ class Wikipedia extends Component {
}
componentDidMount() {
const musicbrainzBaseUrl = "https://musicbrainz.org/ws/2"; // more readable
// let timerId1;
let timerId1;
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
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) { // p435 == musicbrainzWorkId
axios.get(`${musicbrainzBaseUrl}/work/${this.state.wikidata.claims.P435[0].mainsnak.datavalue.value}`, { // get musicbrainz info
params: {
'inc': 'artist-rels url-rels',
'limit': 15,
'offset': 0,
'fmt': 'json'
else { //oof -- no P1651 :(
let title = this.props.title || this.props.title2;
axios.get(wdk.searchEntities(`${title.trim()}`))
.then(wikidataSearchRes => {
try{
this.getWikidataPage(wikidataSearchRes.data.search[0].title)
}
}).then(
musicbrainzRes1 =>
this.setState({ musicbrainz: musicbrainzRes1.data, isMBLoaded: true })
);
}
else {//oof P435 not found in wikidata
axios.get(`${musicbrainzBaseUrl}/work`, { // search on mb by wikidata title
params: {
'query': `work:${this.state.wikidata.labels.en.value}`,
'limit': 1,
'offset': 0,
'fmt': 'json'
}
}).then(musicbrainzRes2 => {
axios.get(`${musicbrainzBaseUrl}/work/${musicbrainzRes2.data.works[0].id}`,
{ // get musicbrainz info on track by previous id
params: {
'inc': 'artist-rels url-rels',
'limit': 15,
'fmt': 'json'
catch(e){
console.error(e)
}
})
.then(
(musicbrainzWorkRes2) =>
this.setState({ musicbrainz: musicbrainzWorkRes2.data, isMBLoaded: true })
);
});
}
});
}
else { //oof
axios.get(`${musicbrainzBaseUrl}/work`, {
params: {
'query': 'undefined' === typeof this.props.title ? this.props.title2 : this.props.title,
'limit': 1,
'offset': 0,
'fmt': 'json'
}
}).then(musicbrainzRes => {
axios.all([
axios.get(wdk.getReverseClaims('P435', musicbrainzRes.data.works[0].id)), // P435 is musicbrainz id
axios.get(`${musicbrainzBaseUrl}/work/${musicbrainzRes.data.works[0].id}`, { // get musicbrainz info
params: {
'inc': 'artist-rels url-rels',
'limit': 15,
'fmt': 'json'
}
})
]).then(
axios.spread((wikidataP435Res, musicbrainzWorkRes) => {
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 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(wikidataUrl.url.resource)) //.then(() => this.setState({ isWikiLoaded: true }));
}
else { // oof
this.findWikiPage()
}
})
)
return new Promise((resolve, reject) => {
timerId1 = window.setInterval(() => {
if (this.state.wikidataQ == undefined || this.state.wikidata == undefined) { }
else{
try {
resolve({
artist: this.state.wikidataQ[this.state.wikidata.claims["P175"][0].mainsnak.datavalue.value.id].labels.en.value.toString(),
genre: this.state.wikidataQ[this.state.wikidata.claims["P136"][0].mainsnak.datavalue.value.id].labels.en.value.toString()
})
}
}).finally(() => {
// let tmp = JSON.parse(localStorage['currentVideoInfo']);
// tmp.id = this.props.videoId;
// tmp.artist = this.state.wikipedia.info.artist;
// tmp.genre = this.state.wikidataQ[this.state.wikidata.claims["P136"][0].mainsnak.datavalue.value.id].labels.en.value;
// console.info(tmp)
// // localStorage.setItem('currentVideoInfo',JSON.stringify(tmp));
this.setState({ isLoaded: true })
});
catch{
resolve({ artist: null, genre: null })
}
}
}, 1000)
})
}).then((res) => {
let tmp = JSON.parse(localStorage['currentVideoInfo']);
window.clearInterval(timerId1);
tmp = {
id: this.props.videoId.toString(),
artist: res.artist,
genre: res.genre
}
localStorage.setItem('currentVideoInfo', JSON.stringify(tmp));
})
.finally(() => this.setState({ isLoaded: true }));
}
@@ -220,11 +261,12 @@ class Wikipedia extends Component {
if (error) {
return <React.Fragment>Error: {error.message}</React.Fragment>;
} else if (!this.state.isLoaded) {
return <React.Fragment>Loading...</React.Fragment>;
return <Col className="text-center">
<div className="lds-ellipsis"><div></div><div></div><div></div><div></div></div>
</Col>;
} else {
return (<>
{/* {isWikiLoaded && wikipedia.desc} */}
<Table bordered variant="dark" hover size="sm">
return (
<Table size="sm">
<tbody>
{isWikiLoaded &&
this.state.wikipediakeys.map(key => (
@@ -241,9 +283,9 @@ class Wikipedia extends Component {
${key[1].labels.en ? key[1].labels.en.value : ""} `}
</td>
<td>{
typeof wikidata.claims[key[0]][0].mainsnak.datavalue.value === "string" ?
typeof wikidata.claims[key[0]][0].mainsnak.datavalue.value === "string" ? // wikidata external
this.getExternalLink(key[0], wikidata.claims[key[0]][0].mainsnak.datavalue.value) :
typeof wikidata.claims[key[0]][0].mainsnak.datavalue.value.id === "string" ?
typeof wikidata.claims[key[0]][0].mainsnak.datavalue.value.id === "string" ? // wikidata Q
<><a target="_blank" rel="noopener noreferrer" href={`https://www.wikidata.org/wiki/${wikidata.claims[key[0]][0].mainsnak.datavalue.value.id}`}>
{`${this.state.wikidataQ[wikidata.claims[key[0]][0].mainsnak.datavalue.value.id].labels.en ?
this.state.wikidataQ[wikidata.claims[key[0]][0].mainsnak.datavalue.value.id].labels.en.value :
@@ -274,7 +316,6 @@ class Wikipedia extends Component {
}
</tbody>
</Table>
</>
);
}
}
+73 -1
View File
@@ -1,9 +1,81 @@
.upperSection{
background-color:#000000;
display: fixed;
}
.blackBg{
background-color:#000000;
}
.downSection{
overflow-y: auto;
overflow-x: hidden;
}
.suggItem:hover{
background-color: #213241;
text-decoration: none;
/* color: */
}
.suggItem:hover h5{
color: #DF691A;
}
.suggItem p{
color: #FFFFFF;
}
/* LOADING ANIMATION */
.lds-ellipsis {
display: inline-block;
position: relative;
width: 64px;
height: 64px;
}
.lds-ellipsis div {
position: absolute;
top: 27px;
width: 11px;
height: 11px;
border-radius: 50%;
background: #fff;
animation-timing-function: cubic-bezier(0, 1, 1, 0);
}
.lds-ellipsis div:nth-child(1) {
left: 6px;
animation: lds-ellipsis1 0.6s infinite;
}
.lds-ellipsis div:nth-child(2) {
left: 6px;
animation: lds-ellipsis2 0.6s infinite;
}
.lds-ellipsis div:nth-child(3) {
left: 26px;
animation: lds-ellipsis2 0.6s infinite;
}
.lds-ellipsis div:nth-child(4) {
left: 45px;
animation: lds-ellipsis3 0.6s infinite;
}
@keyframes lds-ellipsis1 {
0% {
transform: scale(0);
}
100% {
transform: scale(1);
}
}
@keyframes lds-ellipsis3 {
0% {
transform: scale(1);
}
100% {
transform: scale(0);
}
}
@keyframes lds-ellipsis2 {
0% {
transform: translate(0, 0);
}
100% {
transform: translate(19px, 0);
}
}
+3
View File
@@ -3,3 +3,6 @@ a[target=_blank]{
padding-right: 14px;
}
tbody a{
color: #DF691A !important;
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+5 -2
View File
@@ -1,4 +1,6 @@
import 'bootstrap/dist/css/bootstrap.css';
// import 'bootstrap/dist/css/bootstrap.css';
// import './css/bootswatch/darkly/bootstrap.min.css'
import './css/bootswatch/superhero/bootstrap.min.css'
import 'react-app-polyfill/ie9';
//import '@babel/polyfill';
import React from 'react';
@@ -9,13 +11,14 @@ import { HashRouter, BrowserRouter } from 'react-router-dom'; // eslint-disable-
localStorage['lastWatched'] ? function () { }() : localStorage.setItem('lastWatched', JSON.stringify([]))
localStorage['first'] ? function () { }() : localStorage.setItem('first', JSON.stringify([]))
localStorage['lastId'] ? function (){}() : localStorage.setItem('lastId','0J2QdDbelmY')
localStorage['prevId'] ? function () { }() : localStorage.setItem('prevId', '1')
localStorage['lastId'] ? function () { }() : localStorage.setItem('lastId', '0J2QdDbelmY')
localStorage['currentVideoInfo'] ? function () { }() : localStorage.setItem('currentVideoInfo', JSON.stringify({
'id': '0J2QdDbelmY',
'artist': 'Seven Nation Army',
'genre': 'Rock'
}));
localStorage['lastTopic'] ? function () { }() : localStorage.setItem('lastTopic', '/m/04rlf');
ReactDOM.render(<BrowserRouter><App /></BrowserRouter>, document.getElementById('root'));
registerServiceWorker();
+33 -3
View File
@@ -1,7 +1,7 @@
import React, { Component } from 'react';
import axios from "axios";
import createpageToken from 'youtube-page-token';
import {Card,Col} from "react-bootstrap";
import { Card, Col, Media } from "react-bootstrap";
import { Link } from "react-router-dom";
import moment from "moment";
@@ -43,6 +43,7 @@ class RecommenderRandom extends Component{
render() {
const ISO_8601parse = this.ISO_8601parse;
if (window.innerWidth < 992) {
return (<React.Fragment>
{this.state.items.map(function (item, index) {
return (
@@ -51,6 +52,7 @@ class RecommenderRandom extends Component{
<Link
to={{
pathname: '/video/' + item.id.videoId,
search: "?ref=Random"
}}
>
<Card.Img
@@ -60,7 +62,8 @@ class RecommenderRandom extends Component{
<Card.ImgOverlay>
<Card.Title className="bg-dark d-inline text-white">
{item.snippet.title}<br />
{item.snippet.channelTitle} - {ISO_8601parse(item.snippet.publishedAt)}
{item.snippet.channelTitle} - {ISO_8601parse(item.snippet.publishedAt)}<br />
<span>Reccomender: Random</span>
</Card.Title>
</Card.ImgOverlay>
</Link>
@@ -69,6 +72,33 @@ class RecommenderRandom extends Component{
)
})}
</React.Fragment>);
}
}else{
return (
<ul className="list-unstyled">{
this.state.items.map(item => (
<Link
key={item.id.videoId}
as="li" className="media mx-5 my-1 suggItem"
to={{
pathname: `/video/${item.id.videoId}`,
search: '?ref=Random'
}}>
<img
width={240}
height={120}
className="align-self-center mr-3 img-fluid"
src={item.snippet.thumbnails.high.url}
alt={'Thumbnail of ' + item.snippet.title}
/>
<Media.Body>
<h5>{item.snippet.title}</h5>
<p> {item.snippet.channelTitle} - {ISO_8601parse(item.snippet.publishedAt)}</p>
<p>Reccomender: Random</p>
</Media.Body>
</Link>
))
}</ul>
);
}}
}
export default RecommenderRandom;
+38 -13
View File
@@ -1,5 +1,5 @@
import React from 'react';
import { Col, ListGroup, Card, CardDeck } from 'react-bootstrap'; // eslint-disable-line no-unused-vars
import { Col, Card, Media } 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"] }] */
@@ -55,7 +55,6 @@ class Recent extends React.Component {
}
render() {
const { error, isLoaded, items } = this.state;
if (error) {
@@ -65,22 +64,20 @@ class Recent extends React.Component {
</React.Fragment>
);
} else if (!isLoaded) {
return (
<React.Fragment>
<Col>
<p className="text-center">Loading...</p>
</Col>
</React.Fragment>
);
return <Col className="text-center">
<div className="lds-ellipsis"><div></div><div></div><div></div><div></div></div>
</Col>;
} else {
if (window.innerWidth < 992) {
return (
<React.Fragment>
{items.map(item => (
<Col md="4">
<Card key={item.id}>
<Col key={item.id} md="4">
<Card >
<Link
to={{
pathname: '/video/' + item.id,
search: "?ref=Recent"
}}
>
<Card.Img
@@ -90,7 +87,8 @@ class Recent extends React.Component {
<Card.ImgOverlay>
<Card.Title className="bg-dark d-inline text-white">
{item.name}<br />
{item.lastSelected}
<span>Ultima volta visto: {this.ISO_8601parse(item.lastWatched)} </span><br />
<span>Reccomender: Recent</span>
</Card.Title>
</Card.ImgOverlay>
</Link>
@@ -99,7 +97,34 @@ class Recent extends React.Component {
</Col>))}
</React.Fragment>
);
}
}else{
return (
<ul className="list-unstyled">{
this.state.items.map(item => (
<Link
key={item.name}
as="li" className="media mx-5 my-1 suggItem"
to={{
pathname: `/video/${item.name}`,
search: '?ref=Recent'
}}>
<img
width={240}
height={120}
className="align-self-center mr-3 img-fluid"
src={item.thumbnail}
alt={'Thumbnail of ' + item.name}
/>
<Media.Body>
<h5>{item.name}</h5><br />
<p>Ultima volta visto: {this.ISO_8601parse(item.lastWatched)} </p><br />
<p>Reccomender: Recent</p>
</Media.Body>
</Link>
))
}</ul>
);
}}
}
}
+33 -3
View File
@@ -1,7 +1,7 @@
import React, { Component } from 'react';
import axios from 'axios';
import { Link } from "react-router-dom";
import {Card,Col} from "react-bootstrap";
import { Card, Col, Media } from "react-bootstrap";
import moment from "moment";
@@ -62,6 +62,7 @@ class Related extends Component {
render() {
const ISO_8601parse = this.ISO_8601parse;
if (window.innerWidth < 992) {
return (
<React.Fragment>
{this.state.items.map(function (item, index) {
@@ -71,6 +72,7 @@ class Related extends Component {
<Link
to={{
pathname: '/video/' + item.id.videoId,
search: "?ref=Related"
}}
>
<Card.Img
@@ -80,7 +82,8 @@ class Related extends Component {
<Card.ImgOverlay>
<Card.Title className="bg-dark d-inline text-white">
{item.snippet.title}<br />
{item.snippet.channelTitle} - {ISO_8601parse(item.snippet.publishedAt)}
{item.snippet.channelTitle} - {ISO_8601parse(item.snippet.publishedAt)}<br />
<span>Reccomender: Related</span>
</Card.Title>
</Card.ImgOverlay>
</Link>
@@ -90,7 +93,34 @@ class Related extends Component {
})}
</React.Fragment>
);
}
}else{
return (
<ul className="list-unstyled">{
this.state.items.map(item => (
<Link
key={item.id.videoId}
as="li" className="media mx-5 my-1 suggItem"
to={{
pathname: `/video/${item.id.videoId}`,
search: '?ref=Related'
}}>
<img
width={240}
height={120}
className="align-self-center mr-3 img-fluid"
src={item.snippet.thumbnails.high.url}
alt={'Thumbnail of ' + item.snippet.title}
/>
<Media.Body>
<h5>{item.snippet.title}</h5>
<p> {item.snippet.channelTitle} - {ISO_8601parse(item.snippet.publishedAt)}</p>
<p>Reccomender: Related</p>
</Media.Body>
</Link>
))
}</ul>
);
}}
}
Related.propTypes = {
+44 -9
View File
@@ -1,7 +1,7 @@
import React from 'react';
import axios from 'axios';
import { Link } from 'react-router-dom';
import { Card, Col } from 'react-bootstrap';
import { Col, Media, Card } from 'react-bootstrap';
class Search extends React.Component {
@@ -44,7 +44,8 @@ class Search extends React.Component {
// }
componentDidUpdate(prevProps, prevState) {
if (prevProps.match.params.query !== this.props.match.params.query)
if (prevProps.match.params.query !== this.props.match.params.query) {
this.setState({ isLoaded: false })
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: {
@@ -68,6 +69,8 @@ class Search extends React.Component {
)
else
this.youtubeSearch();
}
}
// componentWillUnmount() {
@@ -102,15 +105,46 @@ class Search extends React.Component {
if (this.state.error) {
return <React.Fragment>{this.state.error.message} -- {this.state.error.response.data.error.errors[0].reason} </React.Fragment>;
} else if (!this.state.isLoaded) {
return <React.Fragment>Loading...</React.Fragment>;
return <Col className="text-center">
<div className="lds-ellipsis"><div></div><div></div><div></div><div></div></div>
</Col>;
} else {
if (window.innerWidth > 992) {
return (
<ul className="list-unstyled">{
this.state.res.items.map(item => (
<Link
key={item.id.videoId}
as="li" className="media mx-5 my-1 suggItem"
to={{
pathname: '/video/' + item.id.videoId,
search: "?ref=Search"
}}>
<img
width={240}
height={120}
className="align-self-center mr-3"
src={item.snippet.thumbnails.medium.url}
alt={'Thumbnail of ' + item.snippet.title}
/>
<Media.Body>
<h5>{item.snippet.title}</h5>
<p>{item.snippet.description}</p>
<p>Reccomender: Search</p>
</Media.Body>
</Link>
))
}</ul>
);
}else{
return (
<React.Fragment>
{this.state.res.items.map(item => (<Col key={item.id.videoId} md="4">
<Card>
{this.state.res.items.map(item => (<Col md="4">
<Card key={item.id.videoId}>
<Link
to={{
pathname: '/video/' + item.id.videoId,
search: "?ref=Search"
}}
>
<Card.Img
@@ -119,16 +153,17 @@ class Search extends React.Component {
/>
<Card.ImgOverlay>
<Card.Title className="bg-dark d-inline text-white">
{item.snippet.title}
<p>{item.snippet.title}</p>
<p className='small'>{item.lastSelected}</p>
<p className='small'>Reccomender: Search</p>
</Card.Title>
</Card.ImgOverlay>
</Link>
</Card>
</Col>
))}
</Col>))}
</React.Fragment>
);
}
}}
}
}
+36 -9
View File
@@ -1,10 +1,9 @@
import React from 'react';
import { Col, Card } from 'react-bootstrap'; // eslint-disable-line no-unused-vars
import { Col, Card, Media } 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"] }] */
class fvitali extends React.Component {
state = {
error: null,
@@ -79,13 +78,12 @@ class fvitali extends React.Component {
);
} else if (!isLoaded) {
return (
<React.Fragment>
<Col>
<p className="text-center">Loading...</p>
<Col className="text-center">
<div className="lds-ellipsis"><div></div><div></div><div></div><div></div></div>
</Col>
</React.Fragment>
);
} else {
if (window.innerWidth < 992) {
return (
<React.Fragment>
{items.map(item => (<Col md="4">
@@ -93,6 +91,7 @@ class fvitali extends React.Component {
<Link
to={{
pathname: '/video/' + item.videoID,
search: "?ref=fvitali"
}}
>
<Card.Img
@@ -101,16 +100,44 @@ class fvitali extends React.Component {
/>
<Card.ImgOverlay>
<Card.Title className="bg-dark d-inline text-white">
{item.name}<br/>
{item.lastSelected}
<span>{item.name}</span> <br/>
<span>Reccomender: fvitali</span>
</Card.Title>
</Card.ImgOverlay>
</Link>
</Card>
</Col>))}
</React.Fragment>
);
} else {
return (
<ul className="list-unstyled">{
items.map(item => (
<Link
key={item.videoID}
as="li" className="media mx-5 my-1 suggItem"
to={{
pathname: `/video/${item.videoID}`,
search: '?ref=fvitali'
}}>
<img
width={240}
height={120}
className="align-self-center mr-3 img-fluid"
src={item.thumbnail}
alt={'Thumbnail of ' + item.name}
/>
<Media.Body>
<h5>{item.name}</h5>
<p>Reccomender: fvitali</p>
</Media.Body>
</Link>
))
}</ul>
);
}
}
}
}
+104
View File
@@ -0,0 +1,104 @@
import React, { Component } from 'react';
import axios from 'axios';
import { Card, Col, Media } from "react-bootstrap";
import createpageToken from 'youtube-page-token';
import { Link } from "react-router-dom";
import moment from "moment";
class genreSimilarity extends Component {
state = {
items: []
};
ISO_8601parse(a) {
return moment(a, moment.ISO_8601).format('ddd, DD/MM/YYYY hh:mm:ss');
}
componentDidMount() {
let pos = Math.floor(Math.random() * 100);
let pageToken = createpageToken(pos);
axios.get("https://www.googleapis.com/youtube/v3/search", {
params: {
'part': 'snippet',
'topicId': localStorage['lastTopic'],
'type': 'video',
'maxResults': '21',
'order': 'viewCount',
'pageToken': pageToken,
'key': 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig'
}
}).then(
response => {
this.setState({
items: response.data.items,
})
},
error => {
console.error(error);
}
)
}
render() {
const ISO_8601parse = this.ISO_8601parse;
if (window.innerWidth < 992){
return (<React.Fragment>
{this.state.items.map(function (item, index) {
return (
<Col key={index} md='4'>
<Card>
<Link
to={{
pathname: '/video/' + item.id.videoId,
search: "?ref=genreSimilarity"
}}
>
<Card.Img
src={item.snippet.thumbnails.high.url}
alt={'Thumbnail of ' + item.snippet.title}
/>
<Card.ImgOverlay>
<Card.Title className="bg-dark d-inline text-white">
{item.snippet.title}<br />
{item.snippet.channelTitle}<br />
<span>Reccomender: similarityArtist</span>
</Card.Title>
</Card.ImgOverlay>
</Link>
</Card>
</Col>
)
})}
</React.Fragment>);
}else {
return (
<ul className="list-unstyled">{
this.state.items.map(item => (
<Link
key={item.id.videoId}
as="li" className="media mx-5 my-1 suggItem"
to={{
pathname: `/video/${item.id.videoId}`,
search: '?ref=genreSimilarity'
}}>
<img
width={240}
height={120}
className="align-self-center mr-3 img-fluid"
src={item.snippet.thumbnails.high.url}
alt={'Thumbnail of ' + item.snippet.title}
/>
<Media.Body>
<h5>{item.snippet.title}</h5>
<p> {item.snippet.channelTitle} - {ISO_8601parse(item.snippet.publishedAt)}</p>
<p>Reccomender: genreSimilarity</p>
</Media.Body>
</Link>
))
}</ul>
);
}}
}
export default genreSimilarity;
+64 -50
View File
@@ -1,8 +1,9 @@
import React from 'react';
import { Col, ListGroup, Card, CardDeck } from 'react-bootstrap'; // eslint-disable-line no-unused-vars
import { Col, Media, Card } 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 moment from "moment";
var _ = require('lodash');
class popGlobaleAssoluta extends React.Component {
state = {
@@ -13,70 +14,54 @@ class popGlobaleAssoluta extends React.Component {
};
componentDidMount() {
// listSiti.map(
// sito =>
// axios.get(`http://site${sito}.tw.cs.unibo.it/globpop`, {
// 'params': {
// 'id': this.props.match.params.id
// }
// })
// )
// let listSiti = ['1828', '1829', '1838', '1839', '1846', '1822', '1847', '1831', '1827', '1848', '1824', '1830', '1836', '1850', '1849', '1851', '1861', '1823', '1863', '1834', '1904', '1906', '1901', '1862', '1859'];
let listSiti = ['1828', '1838', '1839', '1846', '1847', '1831', '1827', '1849', '1823', '1863', '1834', '1901', '1859'];
let axiosReq = [];
for(let i=0; i<listSiti.length; i++){
console.log(`http://site${listSiti[i]}.tw.cs.unibo.it/globpop`)
axiosReq.push(axios.get(`http://site${listSiti[i]}.tw.cs.unibo.it/globpop`, {
'params': {
'id': this.props.match.params.id
}
}))
}
Promise.all(axiosReq)
.then(axios.spread((...res) => {
console.log(res.map(x=>x.data))
})
// let listSiti = ['1828', '1829', '1838', '1839', '1846', '1822', '1847', '1831', '1827', '1848', '1824', '1830', '1836', '1850', '1849', '1851', '1861', '1823', '1863', '1834', '1904', '1906', '1901', '1862', '1859', '1841', '1905', '1864', '1840', '1860', '1858', '1835', '1911', '1913', '1826', '1855', '1907', '1912', '1903', '1915', '1854', '1910'];
let listSiti = ['1828', '1838','1839', '1846', '1831', '1827', '1823', '1863', '1834', '1901'];//, '1859', '1841', '1905', '1864', '1860', '1858', '1913', '1855', '1912', '1915', '1854', '1910'];
Promise.all(
listSiti.map(
el => fetch(`http://site${el}.tw.cs.unibo.it/globpop?id=${this.props.match.params.id}`)
.then(res =>
res.json()
)
)
).then(res => {
/* do something with res here... */
console.log(res)
let tmp = res.map(x => x.recommended);
//let tmp2 =tmp.filter(el=>el.length > 0).map(el => el.map(el1 => el1.videoID || el1.videoId) )
console.log(...tmp)
this.getThumbnailsNames(tmp);
});
}
// METODI
getThumbnailsNames(reccomended) {
let idToLookFor = reccomended.map(item => item.videoID);
console.log(reccomended)
let tmp2 =reccomended.filter(el=>el.length > 0).map(el => el.map(el1 => el1.videoID || el1.videoId) )
let idToLookFor =[].concat(...tmp2);
idToLookFor.filter(el=>el.videoID !== undefined || el.videoId !== undefined)
axios.get('https://www.googleapis.com/youtube/v3/videos', {
params: {
part: 'snippet',
id: idToLookFor.toString(),
id: _.uniq(idToLookFor).slice(0,50).toString(),
key: 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig',
fields: 'items(id,snippet/thumbnails/medium,snippet/title)'
fields: 'items(id,snippet/thumbnails/high,snippet/title)'
}
})
.then(
res1 => {
res1.data.items.map(resCurrentValue => {
Object.defineProperties(
reccomended.find(videoItem => {
return videoItem.videoID === resCurrentValue.id;
}),
{
'thumbnail':
{ value: resCurrentValue.snippet.thumbnails.medium.url },
'name':
{ value: resCurrentValue.snippet.title }
});
});
this.setState({
items: res1.data.items,
isLoaded: true,
items: reccomended
});
console.log(res1)
})
}
render() {
const { error, isLoaded, items, headers } = this.state;
const { error, isLoaded, items } = this.state;
if (error) {
return (
<React.Fragment>
@@ -91,7 +76,7 @@ class popGlobaleAssoluta extends React.Component {
</Col>
</React.Fragment>
);
} else {
} else { if (window.innerWidth < 992){
return (
<React.Fragment>
{items.map(item => (<Col md="4">
@@ -99,16 +84,18 @@ class popGlobaleAssoluta extends React.Component {
<Link
to={{
pathname: '/video/' + item.videoID,
search: "?ref=popGlobaleAssoluta"
}}
>
<Card.Img
src={item.thumbnail}
alt={'Thumbnail of ' + item.name}
src={item.snippet.thumbnails.high.url}
alt={'Thumbnail of ' + item.snippet.title}
/>
<Card.ImgOverlay>
<Card.Title className="bg-dark d-inline text-white">
{item.name}<br />
{item.lastSelected}
{item.snippet.title}<br />
{item.snippet.channelTitle}<br />
<span>Reccomender: popGlobaleAssoluta</span>
</Card.Title>
</Card.ImgOverlay>
</Link>
@@ -117,7 +104,34 @@ class popGlobaleAssoluta extends React.Component {
</React.Fragment>
);
}
}else {
return (
<ul className="list-unstyled">{
this.state.items.map(item => (
<Link
key={item.videoID}
as="li" className="media mx-5 my-1 suggItem"
to={{
pathname: `/video/${item.videoID}`,
search: '?ref=popGlobaleAssoluta'
}}>
<img
width={240}
height={120}
className="align-self-center mr-3 img-fluid"
src={item.snippet.thumbnails.high.url}
alt={'Thumbnail of ' + item.snippet.title}
/>
<Media.Body>
<h5>{item.snippet.title}</h5>
<p> {item.snippet.channelTitle}</p>
<p>Reccomender: popGlobaleAssoluta</p>
</Media.Body>
</Link>
))
}</ul>
);
}}
}
}
+145
View File
@@ -0,0 +1,145 @@
import React from 'react';
import axios from 'axios';
import { Link } from 'react-router-dom';
import { Col, Media, Card } from 'react-bootstrap';
class popLocaleAss extends React.Component {
state = {
isLoaded: false,
error: null,
res: null
}
// static getDerivedStateFromProps(nextProps, prevState) {
// }
componentDidMount() {
axios
.get('http://site1854.tw.cs.unibo.it/videotrack')
.then(res => {
this.getThumbnailsNames(res.data.sort((a, b) => a.timesWatched - b.timesWatched).reverse());
}
, error => this.setState({ error }))
}
// shouldComponentUpdate(nextProps, nextState) {
// }
// componentDidUpdate(prevProps, prevState) {
// if (prevProps.match.params !== this.props.match.params) {
// this.setState({ isLoaded: false })
// }
// }
// componentWillUnmount() {
// }
getThumbnailsNames(reccomended) {
let idToLookFor = reccomended.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,snippet/description)'
}
})
.then(
res1 => {
res1.data.items.map(resCurrentValue =>
Object.defineProperties(
reccomended.find(videoItem => {
return videoItem.id === resCurrentValue.id;
}),
{
'thumbnail':
{ value: resCurrentValue.snippet.thumbnails.medium.url },
'name':
{ value: resCurrentValue.snippet.title },
'description':
{ value: resCurrentValue.snippet.description }
})
);
this.setState({
isLoaded: true,
items: reccomended
});
})
}
render() {
if (this.state.error) {
return <React.Fragment>{this.state.error.message} -- {this.state.error.response.data.error.errors[0].reason} </React.Fragment>;
} else if (!this.state.isLoaded) {
return <Col className="text-center">
<div className="lds-ellipsis"><div></div><div></div><div></div><div></div></div>
</Col>;
} else {
if (window.innerWidth > 992){
return (
<ul className="list-unstyled">{
this.state.items.map(item => (
<Link
key={item.id.videoId}
as="li" className="media mx-5 my-1 suggItem"
to={{
pathname: '/video/' + item.id,
search: "?ref=popLocaleAss"
}}>
<img
width={240}
height={120}
className="align-self-center mr-3"
src={item.thumbnail}
alt={'Thumbnail of ' + item.name}
/>
<Media.Body>
<h5>{item.name}</h5>
<p>{item.description.substring(0, 200)}</p>
<p>Visto: {item.timesWatched} volt{item.timesWatched === 1 ?"a":"e"} </p>
<p> Reccomender: popLocaleAss </p>
</Media.Body>
</Link>
))
}</ul>
);
}else {return (<React.Fragment>
{this.state.items.map(function (item, index) {
return (
<Col key={index} md='4'>
<Card>
<Link
to={{
pathname: '/video/' + item.id,
search: "?ref=popLocaleAss"
}}
>
<Card.Img
src={item.thumbnail}
alt={'Thumbnail of ' + item.name}
/>
<Card.ImgOverlay>
<Card.Title className="bg-dark d-inline text-white">
{item.name}<br />
<span>Visto: {item.timesWatched} volt{item.timesWatched === 1 ?"a":"e"} </span><br />
<span> Reccomender: popLocaleAss </span>
</Card.Title>
</Card.ImgOverlay>
</Link>
</Card>
</Col>
)
})}
</React.Fragment>);
}}
}
}
export default popLocaleAss;
+44 -10
View File
@@ -1,5 +1,5 @@
import React from 'react';
import { Col, ListGroup, Card, CardDeck } from 'react-bootstrap'; // eslint-disable-line no-unused-vars
import { Col, Card, Media } 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"] }] */
@@ -18,13 +18,17 @@ class PopRelLoc extends React.Component {
}
componentDidMount() {
let tmp = JSON.parse(localStorage.getItem('lastWatched'));
let j=tmp.findIndex(el=>el.id === localStorage["lastId"]);
//this.getThumbnailsNames(tmp[j].prevVideos);
if (tmp.length === 0 || localStorage["prevId"] === '1')
{this.getThumbnailsNames(JSON.parse(localStorage.getItem('first')))}
else
{this.getThumbnailsNames(tmp[j].prevVideos)}
axios.get("http://site1854.tw.cs.unibo.it/videotrack",{
params: {
"prevId" : localStorage['lastId']
}
}).then(res=>{
this.getThumbnailsNames(res.data)
this.setState({
items : res.data
})
},
error=>console.error(error))
}
@@ -80,6 +84,7 @@ class PopRelLoc extends React.Component {
</React.Fragment>
);
} else {
if (window.innerWidth < 992) {
return (
<React.Fragment>
{items.map(item => (
@@ -88,6 +93,7 @@ class PopRelLoc extends React.Component {
<Link
to={{
pathname: '/video/' + item.id,
search: "?ref=popRelLoc"
}}
>
<Card.Img
@@ -97,7 +103,8 @@ class PopRelLoc extends React.Component {
<Card.ImgOverlay>
<Card.Title className="bg-dark d-inline text-white">
{item.name}<br />
{item.lastSelected}
<span>Visto: {item.timesWatched} volt{item.timesWatched === 1 ?"a":"e"} </span><br />
<span> Reccomender: popRelLoc </span>
</Card.Title>
</Card.ImgOverlay>
</Link>
@@ -106,7 +113,34 @@ class PopRelLoc extends React.Component {
</Col>))}
</React.Fragment>
);
}
}else{
return (
<ul className="list-unstyled">{
this.state.items.map(item => (
<Link
key={item.id.videoId}
as="li" className="media mx-5 my-1 suggItem"
to={{
pathname: '/video/' + item.id,
search: "?ref=popRelLoc"
}}>
<img
width={240}
height={120}
className="align-self-center mr-3"
src={item.thumbnail}
alt={'Thumbnail of ' + item.name}
/>
<Media.Body>
<h5>{item.name}</h5>
<p>Visto: {item.timesWatched} volt{item.timesWatched === 1 ?"a":"e"} </p>
<p> Reccomender: popRelLoc </p>
</Media.Body>
</Link>
))
}</ul>
);
}}
}
}
+148
View File
@@ -0,0 +1,148 @@
import React from 'react';
import axios from 'axios';
import { Link } from 'react-router-dom';
import { Col, Media, Card } from 'react-bootstrap';
class similarityArtist extends React.Component {
state = {
isLoaded: false,
error: null,
res: null
}
// static getDerivedStateFromProps(nextProps, prevState) {
// }
componentDidMount() {
let timerId1;
let promise = new Promise((resolve, reject) => {
timerId1 = window.setInterval(() => {
if (localStorage['lastId'] === JSON.parse(localStorage['currentVideoInfo']).id)
resolve(true)
}, 1000)
})
promise.then(() => {
window.clearInterval(timerId1);
this.setState({ artist: JSON.parse(localStorage['currentVideoInfo']).artist })
axios.get('https://www.googleapis.com/youtube/v3/search', {
params: {
'part': 'snippet',
'q': JSON.parse(localStorage['currentVideoInfo']).artist,
'videoEmbeddable': 'true',
'type': 'video',
'maxResults': 15,
'topicId': '/m/04rlf, /m/02jjt',
'key': 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig'
}
}).then(
res => {
let j = res.data.items.findIndex(el => el.id.videoId === localStorage['lastId'])
if (j >= 0)
res.data.items.splice(j, 1);
this.setState({
res: res.data,
isLoaded: true
})
console.log(res);
}
,
error => this.setState({
error
})
)
})
}
// shouldComponentUpdate(nextProps, nextState) {
// }
// componentDidUpdate(prevProps, prevState) {
// if (prevProps.match.params !== this.props.match.params) {
// this.setState({ isLoaded: false })
// }
// }
// componentWillUnmount() {
// }
render() {
if (this.state.error) {
return <React.Fragment>{this.state.error.message} -- {this.state.error.response.data.error.errors[0].reason} </React.Fragment>;
} else if (!this.state.isLoaded) {
return <Col className="text-center">
<div className="lds-ellipsis"><div></div><div></div><div></div><div></div></div>
</Col>;
} else {
if (window.innerWidth > 992) {
return (
<>
<h4>Artist Similarity: {this.state.artist}</h4>
<ul className="list-unstyled">{
this.state.res.items.map(item => (
<Link
key={item.id.videoId}
as="li" className="media mx-5 my-1 suggItem"
to={{
pathname: '/video/' + item.id.videoId,
search: "?ref=similarityArtist"
}}>
<img
width={240}
height={120}
className="align-self-center mr-3"
src={item.snippet.thumbnails.medium.url}
alt={'Thumbnail of ' + item.snippet.title}
/>
<Media.Body>
<h5>{item.snippet.title}</h5>
<p>{item.snippet.description}</p>
<p>Reccomender: similarityArtist</p>
</Media.Body>
</Link>
))
}</ul>
</>
);
}else{
return (<React.Fragment>
{this.state.res.items.map(function (item, index) {
return (
<Col key={index} md='4'>
<Card>
<Link
to={{
pathname: '/video/' + item.id.videoId,
search: "?ref=similarityArtist"
}}
>
<Card.Img
src={item.snippet.thumbnails.high.url}
alt={'Thumbnail of ' + item.snippet.title}
/>
<Card.ImgOverlay>
<Card.Title className="bg-dark d-inline text-white">
{item.snippet.title}<br />
{item.snippet.channelTitle}<br />
<span>Reccomender: similarityArtist</span>
</Card.Title>
</Card.ImgOverlay>
</Link>
</Card>
</Col>
)
})}
</React.Fragment>);
}}
}
}
export default similarityArtist;