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 // GET /globpop
app.get('/globpop', (req, res) => { 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 // OPTIONS /videotrack
@@ -62,8 +114,32 @@ low(new FileAsync(__dirname + '/db.json')) // production
// GET /videotrack // GET /videotrack
app.get('/videotrack', (req, res) => { app.get('/videotrack', (req, res) => {
const videos = db.get('videos'); res.set({
req.query.id ? res.send(videos.getById(req.query.id).value()) : res.send(videos.value()) '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 // POST /videotrack
@@ -71,19 +147,38 @@ low(new FileAsync(__dirname + '/db.json')) // production
res.set({ res.set({
'Access-Control-Allow-Origin': '*' '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 videos = db.get('videos');
const row = videos.getById(req.body.id); const row = videos.getById(req.body.id);
if (row.value()) { if (row.value()) {
row row
.update('timesWatched', (n) => ++n) .update('timesWatched', (n) => ++n)
.update('lastWatched', () => new Date().toISOString()) .update('lastWatched', () => new Date().toISOString())
.update('reason', (n) => setReason(req.body.reason, n, req.body.prevId))
.write() .write()
.then(output => res.send(output)) .then(output => res.send(200, output))
} else { } else {
let newRow = { let newRow = {
"id": req.body.id.toString(), "id": req.body.id.toString(),
"timesWatched": 1, "timesWatched": 1,
"lastWatched": new Date().toISOString(), "lastWatched": new Date().toISOString(),
"reason": setReason(req.body.reason, [], req.body.prevId)
} }
videos.push(newRow).last().write().then(output => res.send(200, output)) videos.push(newRow).last().write().then(output => res.send(200, output))
} }
@@ -94,5 +189,8 @@ low(new FileAsync(__dirname + '/db.json')) // production
}) })
.then(() => { .then(() => {
app.use(express.static(__dirname + '/build')); // serve static build site 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 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", "name": "hazetv-alfatube-1",
"version": "0.1.0", "version": "0.1.1",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@@ -5879,13 +5879,11 @@
}, },
"balanced-match": { "balanced-match": {
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true
"optional": true
}, },
"brace-expansion": { "brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0",
"concat-map": "0.0.1" "concat-map": "0.0.1"
@@ -5898,18 +5896,15 @@
}, },
"code-point-at": { "code-point-at": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true, "bundled": true
"optional": true
}, },
"concat-map": { "concat-map": {
"version": "0.0.1", "version": "0.0.1",
"bundled": true, "bundled": true
"optional": true
}, },
"console-control-strings": { "console-control-strings": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true, "bundled": true
"optional": true
}, },
"core-util-is": { "core-util-is": {
"version": "1.0.2", "version": "1.0.2",
@@ -6012,8 +6007,7 @@
}, },
"inherits": { "inherits": {
"version": "2.0.3", "version": "2.0.3",
"bundled": true, "bundled": true
"optional": true
}, },
"ini": { "ini": {
"version": "1.3.5", "version": "1.3.5",
@@ -6023,7 +6017,6 @@
"is-fullwidth-code-point": { "is-fullwidth-code-point": {
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"number-is-nan": "^1.0.0" "number-is-nan": "^1.0.0"
} }
@@ -6036,20 +6029,17 @@
"minimatch": { "minimatch": {
"version": "3.0.4", "version": "3.0.4",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
} }
}, },
"minimist": { "minimist": {
"version": "0.0.8", "version": "0.0.8",
"bundled": true, "bundled": true
"optional": true
}, },
"minipass": { "minipass": {
"version": "2.2.4", "version": "2.2.4",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"safe-buffer": "^5.1.1", "safe-buffer": "^5.1.1",
"yallist": "^3.0.0" "yallist": "^3.0.0"
@@ -6066,7 +6056,6 @@
"mkdirp": { "mkdirp": {
"version": "0.5.1", "version": "0.5.1",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"minimist": "0.0.8" "minimist": "0.0.8"
} }
@@ -6139,8 +6128,7 @@
}, },
"number-is-nan": { "number-is-nan": {
"version": "1.0.1", "version": "1.0.1",
"bundled": true, "bundled": true
"optional": true
}, },
"object-assign": { "object-assign": {
"version": "4.1.1", "version": "4.1.1",
@@ -6150,7 +6138,6 @@
"once": { "once": {
"version": "1.4.0", "version": "1.4.0",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"wrappy": "1" "wrappy": "1"
} }
@@ -6256,7 +6243,6 @@
"string-width": { "string-width": {
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"code-point-at": "^1.0.0", "code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0", "is-fullwidth-code-point": "^1.0.0",
+1 -1
View File
@@ -43,7 +43,7 @@
"browserslist": [ "browserslist": [
">0.2%", ">0.2%",
"not dead", "not dead",
"not ie <= 11", "not ie <= 8",
"not op_mini all" "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 { Container, Row, Col, Image } from 'react-bootstrap';
import './css/AboutUs.css'; import './css/AboutUs.css';
export default class Home extends Component { export default class AboutUs extends Component {
render() { render() {
return ( return (
<Container> <Container>
@@ -10,17 +10,33 @@ export default class Home extends Component {
<Col xs={12} sm={4} className="person-wrapper"> <Col xs={12} sm={4} className="person-wrapper">
<Image src="assets/person-1.jpg" roundedCircle className="profile-pic" /> <Image src="assets/person-1.jpg" roundedCircle className="profile-pic" />
<h3>Matteo Scorzafava</h3> <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>
<Col xs={12} sm={4} className="person-wrapper"> <Col xs={12} sm={4} className="person-wrapper">
<Image src="assets/person-2.jpg" roundedCircle className="profile-pic" /> <Image src="assets/person-2.jpg" roundedCircle className="profile-pic" />
<h3>Simone Ferrari</h3> <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>
<Col xs={12} sm={4} className="person-wrapper"> <Col xs={12} sm={4} className="person-wrapper">
<Image src="assets/person-3.jpg" roundedCircle className="profile-pic" /> <Image src="assets/person-3.jpg" roundedCircle className="profile-pic" />
<h3>Gregorio Giacchetti</h3> <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> </Col>
</Row> </Row>
</Container> </Container>
+11 -11
View File
@@ -34,19 +34,17 @@ class App extends React.Component {
exact: true, exact: true,
strict: false strict: false
}); });
if (prevState.videoId !== null){
if (idMatch && idMatch.params.id !== prevState.videoId) { if (idMatch && idMatch.params.id !== prevState.videoId) {
localStorage.setItem('prevId', prevState.videoId) localStorage.setItem('prevId', prevState.videoId)
localStorage.setItem('lastId', idMatch.params.id) localStorage.setItem('lastId', idMatch.params.id)
return { videoId: idMatch.params.id }; return { videoId: idMatch.params.id };
} }
else { else {
if (idMatch && idMatch.params.id !== prevState.videoId) {
localStorage.setItem('lastId', idMatch.params.id)
return { videoId: idMatch.params.id };
}
return null; return null;
}}}
}
}
render() { render() {
@@ -58,16 +56,18 @@ class App extends React.Component {
<Row className="upperSection"> <Row className="upperSection">
<Col <Col
xs="12" xs="12"
lg={this.state.isInfoToggled ? { span: 6, offset: 0, order: 2 } : { span: 7, offset: 1, order: 2 }} lg={this.state.isInfoToggled ? { span: 8, offset: 0, order: 2 } : { span: 9, offset: 0, order: 2 }}
className="align-content-center pt-2 p-1 pr-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 }) }}> <ReactHeight onHeightReady={height => { this.setState({ playerHeight: height }) }}>
<VideoPlayer videoId={this.state.videoId} /> <VideoPlayer videoId={this.state.videoId} />
</ReactHeight> </ReactHeight>
</Col> </Col>
</Col>
<Col <Col
xs="12" xs="12"
lg={this.state.isInfoToggled ? { span: 5, order: 1 } : { span: 3, order: 1 }} lg={this.state.isInfoToggled ? { span: 4, order: 1 } : { span: 3, order: 1 }}
className="p-0 p-xs-0" className={this.state.isInfoToggled ? "" : "blackBg"}
style={window.innerWidth < 992 ? style={window.innerWidth < 992 ?
{ 'overflow': "auto", 'display': 'fixed', 'maxHeight': this.state.playerHeight * 1.4 + 'px' } : { 'overflow': "auto", 'display': 'fixed', 'maxHeight': this.state.playerHeight * 1.4 + 'px' } :
{ 'overflow': "auto", 'maxHeight': `${this.state.playerHeight}px` }}> { 'overflow': "auto", 'maxHeight': `${this.state.playerHeight}px` }}>
@@ -89,7 +89,7 @@ class App extends React.Component {
</Collapse> </Collapse>
</Col> </Col>
</Row> </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> <Switch>
<Route exact path='/' component={VideoList} /> <Route exact path='/' component={VideoList} />
<Route path={"/video/:id"} component={Suggestion} /> <Route path={"/video/:id"} component={Suggestion} />
+6 -3
View File
@@ -1,5 +1,4 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Row } from 'react-bootstrap';
import { Switch, Route } from 'react-router'; import { Switch, Route } from 'react-router';
import Random from './reccomenders/Random'; import Random from './reccomenders/Random';
import Related from './reccomenders/Related'; import Related from './reccomenders/Related';
@@ -7,7 +6,10 @@ import Search from './reccomenders/Search';
import fvitali from './reccomenders/fvitali'; import fvitali from './reccomenders/fvitali';
import popGlobaleAssoluta from './reccomenders/popGlobaleAssoluta'; import popGlobaleAssoluta from './reccomenders/popGlobaleAssoluta';
import Recent from './reccomenders/Recent'; import Recent from './reccomenders/Recent';
import similarityArtist from './reccomenders/similarityArtist';
import popLocaleAss from './reccomenders/popLocaleAss';
import PopRelLoc from './reccomenders/popRelLoc'; import PopRelLoc from './reccomenders/popRelLoc';
import genreSimilarity from './reccomenders/genreSimilarity';
// and so on.. // and so on..
@@ -36,18 +38,19 @@ class Suggestion extends Component {
render() { render() {
return ( return (
<React.Fragment> <React.Fragment>
<Row>
<Switch> <Switch>
<Route path='/video/:id/genreSimilarity' component={genreSimilarity} />
<Route path='/video/:id/vitali' component={fvitali} /> <Route path='/video/:id/vitali' component={fvitali} />
<Route path='/search/:query' component={Search} /> <Route path='/search/:query' component={Search} />
<Route path='/video/:id/random' component={Random} /> <Route path='/video/:id/random' component={Random} />
<Route path='/video/:id/popGlobalAssoluta' component={popGlobaleAssoluta} /> <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/recent' component={Recent} />
<Route path='/video/:id/similarityArtist' component={similarityArtist} />
<Route path='/video/:id/popRelLoc' component={PopRelLoc} /> <Route path='/video/:id/popRelLoc' component={PopRelLoc} />
{/* lasciare questo per ultimo */} {/* lasciare questo per ultimo */}
<Route component={Related} /> <Route component={Related} />
</Switch> </Switch>
</Row>
</React.Fragment> </React.Fragment>
); );
} }
+9 -21
View File
@@ -22,15 +22,15 @@ class TopBar extends Component {
} }
handleSubmit = event => { handleSubmit = event => {
event.preventDefault(); event.preventDefault();
event.target.reset(); // event.target.reset();
this.props.history.push('/search/' + this.state.query); this.props.history.push('/search/' + this.state.query);
} }
render() { render() {
return ( return (
<React.Fragment> <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> <Navbar.Brand>
<Link to="/">HazeTV</Link> <Link className="text-light" to="/">HazeTV</Link>
</Navbar.Brand> </Navbar.Brand>
<Navbar.Toggle aria-controls="basic-navbar-nav" /> <Navbar.Toggle aria-controls="basic-navbar-nav" />
<Navbar.Collapse id="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> <Link to={{ pathname: `/video/${localStorage['lastId']}/related` }} className="text-light nav-link">Related</Link>
{<NavDropdown title="Similarity" id="basic-nav-dropdown" > {<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 Artist
</Link> </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 Genre
</Link> </Link>
</NavDropdown>} </NavDropdown>}
{<NavDropdown title="Popolarità locale" id="basic-nav-dropdown" > {<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 Assoluta
</Link> </Link>
<Link to={{ pathname: `/video/${localStorage['lastId']}/popRelLoc` }} className="text-dark nav-link"> <Link to={{ pathname: `/video/${localStorage['lastId']}/popRelLoc` }} className="text-light 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">
Relativa Relativa
</Link> </Link>
</NavDropdown>} </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> </Nav>
<form className="form-inline" onSubmit={this.handleSubmit}> <form className="form-inline" onSubmit={this.handleSubmit}>
@@ -87,7 +75,7 @@ class TopBar extends Component {
className="mr-sm-2" className="mr-sm-2"
onChange={this.handleChange} onChange={this.handleChange}
/> />
<Button type="submit" variant="outline-success">Search</Button> <Button type="submit" variant="secondary">Search</Button>
</form> </form>
</Navbar.Collapse> </Navbar.Collapse>
</Navbar> </Navbar>
+10 -4
View File
@@ -50,11 +50,14 @@ class VideoInfo extends React.Component {
comments: commentThreadResponse.data.items, comments: commentThreadResponse.data.items,
isLoaded: true 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 => { }), error => {
console.error(error); console.error(error);
this.setState({ this.setState({
isLoaded: true, error,
error isLoaded: true
}); });
}); });
} }
@@ -64,14 +67,17 @@ class VideoInfo extends React.Component {
const momentDuration = this.momentDuration; const momentDuration = this.momentDuration;
const ISO_8601parse = this.ISO_8601parse; const ISO_8601parse = this.ISO_8601parse;
if (error) { if (error) {
let htmlRegEx = /<\/?\w+((\s+\w+(\s*=\s*(?:".*?"|'.*?'|[\^'">\s]+))?)+\s*|\s*)\/?>/gm;
return ( return (
<span className="text-white"> <span className="text-white">
<span>{}</span> <span>{}</span>
Error: {error.message} -- Cannot get {error.config.url} Error: {error.message} -- {error.response.data && error.response.data.error.message.replace(htmlRegEx, '')}
</span> </span>
); );
} else if (!isLoaded) { } 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 { } else {
return ( return (
<React.Fragment> <React.Fragment>
+35 -10
View File
@@ -1,5 +1,5 @@
import React from 'react'; 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 axios from 'axios'; // eslint-disable-line no-unused-vars
import { Link } from 'react-router-dom'; // 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"] }] */ /*eslint no-console: ["error", { allow: ["warn", "error", "info"] }] */
@@ -81,8 +81,10 @@ class VideoList extends React.Component {
return videoItem.videoID === resCurrentValue.id; return videoItem.videoID === resCurrentValue.id;
}), }),
'thumbnail', 'thumbnail',
{ value: resCurrentValue.snippet.thumbnails.medium.url, {
enumerable: true } value: resCurrentValue.snippet.thumbnails.medium.url,
enumerable: true
}
) )
); );
this.setState({ this.setState({
@@ -113,13 +115,9 @@ class VideoList extends React.Component {
</React.Fragment> </React.Fragment>
); );
} else if (!isLoaded) { } else if (!isLoaded) {
return ( return <Col className="text-center">
<React.Fragment> <div className="lds-ellipsis"><div></div><div></div><div></div><div></div></div>
<Col> </Col>;
<p className="text-center">Loading...</p>
</Col>
</React.Fragment>
);
} else { } else {
return ( return (
<React.Fragment> <React.Fragment>
@@ -152,6 +150,33 @@ class VideoList extends React.Component {
</Col> </Col>
))} ))}
</React.Fragment> </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, promise1: null,
promise2: null, promise2: Promise,
outsideReject1: null, outsideReject1: null,
outsideReject2: null outsideReject2: null
}; };
@@ -78,7 +78,7 @@ class VideoPlayer extends React.Component {
timerId1 = window.setInterval(() => { timerId1 = window.setInterval(() => {
if (event.target.getCurrentTime() > 15) if (event.target.getCurrentTime() > 15)
resolve(event.target.getVideoData().video_id); resolve(event.target.getVideoData().video_id);
}, 1000); }, 500);
this.setState({ outsideReject1: reject }); this.setState({ outsideReject1: reject });
}) })
}); });
@@ -86,21 +86,23 @@ class VideoPlayer extends React.Component {
.then( .then(
videoIdWatched => { videoIdWatched => {
// post request to local db // post request to local db
let reason = new URLSearchParams(this.props.location.search).get("ref");
axios axios
.post('http://site1854.tw.cs.unibo.it/videotrack', { .post('http://site1854.tw.cs.unibo.it/videotrack', {
id: videoIdWatched.toString() id: videoIdWatched.toString(),
reason: reason || undefined,
prevId: localStorage['prevId']
}) })
.then( .then(
response => console.info(response.data), response => console.info(response.data),
error => this.setState({ error })//console.error(error, videoIdWatched.toString()) 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 tmp = JSON.parse(localStorage.getItem('lastWatched'))
let j = tmp.findIndex(el => el.id.toString() === videoIdWatched.toString()) let j = tmp.findIndex(el => el.id.toString() === videoIdWatched.toString())
if (j < 0) { if (j < 0) {
if (localStorage['prevId']==='1') if (localStorage['prevId'] === '1') {
{
//per primo video //per primo video
tmp.push({ tmp.push({
'id': videoIdWatched.toString(), 'id': videoIdWatched.toString(),
@@ -120,15 +122,6 @@ class VideoPlayer extends React.Component {
} }
} }
else { 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 //altre volte
tmp[j].timesWatched++; tmp[j].timesWatched++;
tmp[j].lastWatched = new Date(); tmp[j].lastWatched = new Date();
@@ -136,9 +129,9 @@ class VideoPlayer extends React.Component {
if (z < 0) { if (z < 0) {
tmp[j].prevVideos.push({ tmp[j].prevVideos.push({
'id': localStorage["prevId"].toString() 'id': localStorage["prevId"].toString()
})} })
}
//}
} }
tmp.sort((a, b) => new Date(b.lastWatched).getTime() - new Date(a.lastWatched).getTime()); 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)); localStorage.setItem('lastWatched', JSON.stringify(tmp));
//.finally(()=>{}) //.finally(()=>{})
clearInterval(timerId1); clearInterval(timerId1);
return new Promise ((resolve,reject) => resolve(videoIdWatched))
}, },
error => console.error(error) error => console.error(error)
) )
.finally((id) => this.setState({ promise1: null, outsideReject1: null }));
.finally(() => this.setState({ promise1: null, outsideReject1: null }));
break; break;
case 5: case 5:
if (this.state.promise1) if (this.state.promise1)
this.state.outsideReject1('Video changed'); this.state.outsideReject1('Video changed');
break; break;
default: default:
break; 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); _onStateChange = this._onStateChange.bind(this);
+144 -103
View File
@@ -3,9 +3,10 @@ import { Link } from 'react-router-dom';
import wikijs from 'wikijs'; import wikijs from 'wikijs';
import wdk from 'wikidata-sdk'; import wdk from 'wikidata-sdk';
import axios from 'axios'; import axios from 'axios';
import { Table } from 'react-bootstrap'; import { Table, Col } from 'react-bootstrap';
import moment from 'moment'; import moment from 'moment';
import "./css/Wikipedia.css" import "./css/Wikipedia.css"
/*eslint no-console: ["error", { allow: ["warn", "error"] }] */
class Wikipedia extends Component { class Wikipedia extends Component {
@@ -40,9 +41,89 @@ class Wikipedia extends Component {
case "P1651": // youtubeid case "P1651": // youtubeid
return (<Link to={{ pathname: `/video/${value}` }}>{`${value}`}</Link>) return (<Link to={{ pathname: `/video/${value}` }}>{`${value}`}</Link>)
case "P2581": 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: 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) .map(x => wikidatatmp.claims[x][0].mainsnak.datavalue.value.id)
.filter(x => typeof x === 'string'), 'en')) .filter(x => typeof x === 'string'), 'en'))
]) ])
.then(axios.spread((resKey, resQ) => { .then(
axios.spread((resKey, resQ) => {
this.setState({ this.setState({
wikidatakeys: Object.entries(resKey.data.entities), wikidatakeys: Object.entries(resKey.data.entities),
wikidataQ: resQ.data.entities, wikidataQ: resQ.data.entities,
isWDataLoaded: true 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) if (wikidatatmp.sitelinks.enwiki)
wikijs() wikijs()
.page(wikidatatmp.sitelinks.enwiki.title) .page(wikidatatmp.sitelinks.enwiki.title)
.then(page => Promise.all([page.fullInfo(), page.summary()])) .then(page => Promise.all([page.fullInfo()]))
.then(wikipediaRes => this.setState({ .then(wikipediaRes => this.setState({
wikipedia: { wikipedia: {
"desc": wikipediaRes[1], // "desc": wikipediaRes[1],
"info": wikipediaRes[0].general "info": wikipediaRes[0].general
}, },
wikipediakeys: Object.keys(wikipediaRes[0].general), wikipediakeys: Object.keys(wikipediaRes[0].general),
isWikiLoaded: true isWikiLoaded: true
})) }))
else { else {
console.info('called here')
this.findWikiPage(); this.findWikiPage();
} }
}, error => console.error(error)) }, error => console.error(error))
} }
findWikiPage = () => { 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)`; 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)`}`;
console.info(wikiquery)
return wikijs() return wikijs()
.find(wikiquery) .find(wikiquery)
.then(res => { .then(res => {
console.info(res, 'a'); return Promise.all([res.fullInfo()]);
return Promise.all([res.fullInfo(), res.summary()]);
}) // find by props.title (props.artist song) }) // find by props.title (props.artist song)
.then(wikipediaRes => this.setState({ .then(wikipediaRes => this.setState({
wikipedia: { wikipedia: {
"desc": wikipediaRes[1],
"info": wikipediaRes[0].general "info": wikipediaRes[0].general
}, },
wikipediakeys: Object.keys(wikipediaRes[0].general), wikipediakeys: Object.keys(wikipediaRes[0].general),
@@ -106,99 +196,50 @@ class Wikipedia extends Component {
} }
componentDidMount() { 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 axios.get(wdk.getReverseClaims('P1651', this.props.videoId)) // P1651 is youtube_video_id property
.then(wikidataP1651Res => { .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 this.getWikidataPage(wdk.simplify.sparqlResults(wikidataP1651Res.data))// set in state wikidata
.then(() => { else { //oof -- no P1651 :(
if (this.state.wikidata.claims.P435) { // p435 == musicbrainzWorkId let title = this.props.title || this.props.title2;
axios.get(`${musicbrainzBaseUrl}/work/${this.state.wikidata.claims.P435[0].mainsnak.datavalue.value}`, { // get musicbrainz info axios.get(wdk.searchEntities(`${title.trim()}`))
params: { .then(wikidataSearchRes => {
'inc': 'artist-rels url-rels', try{
'limit': 15, this.getWikidataPage(wikidataSearchRes.data.search[0].title)
'offset': 0,
'fmt': 'json'
} }
}).then( catch(e){
musicbrainzRes1 => console.error(e)
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'
} }
}) })
.then(
(musicbrainzWorkRes2) =>
this.setState({ musicbrainz: musicbrainzWorkRes2.data, isMBLoaded: true })
);
});
} }
}); return new Promise((resolve, reject) => {
} timerId1 = window.setInterval(() => {
else { //oof if (this.state.wikidataQ == undefined || this.state.wikidata == undefined) { }
axios.get(`${musicbrainzBaseUrl}/work`, { else{
params: { try {
'query': 'undefined' === typeof this.props.title ? this.props.title2 : this.props.title, resolve({
'limit': 1, artist: this.state.wikidataQ[this.state.wikidata.claims["P175"][0].mainsnak.datavalue.value.id].labels.en.value.toString(),
'offset': 0, genre: this.state.wikidataQ[this.state.wikidata.claims["P136"][0].mainsnak.datavalue.value.id].labels.en.value.toString()
'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()
}
})
)
}) })
} }
catch{
}).finally(() => { resolve({ artist: null, genre: null })
// let tmp = JSON.parse(localStorage['currentVideoInfo']); }
// tmp.id = this.props.videoId; }
// tmp.artist = this.state.wikipedia.info.artist; }, 1000)
// tmp.genre = this.state.wikidataQ[this.state.wikidata.claims["P136"][0].mainsnak.datavalue.value.id].labels.en.value; })
// console.info(tmp) }).then((res) => {
// // localStorage.setItem('currentVideoInfo',JSON.stringify(tmp)); let tmp = JSON.parse(localStorage['currentVideoInfo']);
this.setState({ isLoaded: true }) 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) { if (error) {
return <React.Fragment>Error: {error.message}</React.Fragment>; return <React.Fragment>Error: {error.message}</React.Fragment>;
} else if (!this.state.isLoaded) { } 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 { } else {
return (<> return (
{/* {isWikiLoaded && wikipedia.desc} */} <Table size="sm">
<Table bordered variant="dark" hover size="sm">
<tbody> <tbody>
{isWikiLoaded && {isWikiLoaded &&
this.state.wikipediakeys.map(key => ( this.state.wikipediakeys.map(key => (
@@ -241,9 +283,9 @@ class Wikipedia extends Component {
${key[1].labels.en ? key[1].labels.en.value : ""} `} ${key[1].labels.en ? key[1].labels.en.value : ""} `}
</td> </td>
<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) : 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}`}> <><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 ?
this.state.wikidataQ[wikidata.claims[key[0]][0].mainsnak.datavalue.value.id].labels.en.value : this.state.wikidataQ[wikidata.claims[key[0]][0].mainsnak.datavalue.value.id].labels.en.value :
@@ -274,7 +316,6 @@ class Wikipedia extends Component {
} }
</tbody> </tbody>
</Table> </Table>
</>
); );
} }
} }
+73 -1
View File
@@ -1,9 +1,81 @@
.upperSection{ .upperSection{
background-color:#000000;
display: fixed; display: fixed;
} }
.blackBg{
background-color:#000000;
}
.downSection{ .downSection{
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; 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; 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 'react-app-polyfill/ie9';
//import '@babel/polyfill'; //import '@babel/polyfill';
import React from 'react'; 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['lastWatched'] ? function () { }() : localStorage.setItem('lastWatched', JSON.stringify([]))
localStorage['first'] ? function () { }() : localStorage.setItem('first', 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['prevId'] ? function () { }() : localStorage.setItem('prevId', '1')
localStorage['lastId'] ? function () { }() : localStorage.setItem('lastId', '0J2QdDbelmY')
localStorage['currentVideoInfo'] ? function () { }() : localStorage.setItem('currentVideoInfo', JSON.stringify({ localStorage['currentVideoInfo'] ? function () { }() : localStorage.setItem('currentVideoInfo', JSON.stringify({
'id': '0J2QdDbelmY', 'id': '0J2QdDbelmY',
'artist': 'Seven Nation Army', 'artist': 'Seven Nation Army',
'genre': 'Rock' 'genre': 'Rock'
})); }));
localStorage['lastTopic'] ? function () { }() : localStorage.setItem('lastTopic', '/m/04rlf');
ReactDOM.render(<BrowserRouter><App /></BrowserRouter>, document.getElementById('root')); ReactDOM.render(<BrowserRouter><App /></BrowserRouter>, document.getElementById('root'));
registerServiceWorker(); registerServiceWorker();
+33 -3
View File
@@ -1,7 +1,7 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import axios from "axios"; import axios from "axios";
import createpageToken from 'youtube-page-token'; 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 { Link } from "react-router-dom";
import moment from "moment"; import moment from "moment";
@@ -43,6 +43,7 @@ class RecommenderRandom extends Component{
render() { render() {
const ISO_8601parse = this.ISO_8601parse; const ISO_8601parse = this.ISO_8601parse;
if (window.innerWidth < 992) {
return (<React.Fragment> return (<React.Fragment>
{this.state.items.map(function (item, index) { {this.state.items.map(function (item, index) {
return ( return (
@@ -51,6 +52,7 @@ class RecommenderRandom extends Component{
<Link <Link
to={{ to={{
pathname: '/video/' + item.id.videoId, pathname: '/video/' + item.id.videoId,
search: "?ref=Random"
}} }}
> >
<Card.Img <Card.Img
@@ -60,7 +62,8 @@ class RecommenderRandom extends Component{
<Card.ImgOverlay> <Card.ImgOverlay>
<Card.Title className="bg-dark d-inline text-white"> <Card.Title className="bg-dark d-inline text-white">
{item.snippet.title}<br /> {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.Title>
</Card.ImgOverlay> </Card.ImgOverlay>
</Link> </Link>
@@ -69,6 +72,33 @@ class RecommenderRandom extends Component{
) )
})} })}
</React.Fragment>); </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; export default RecommenderRandom;
+38 -13
View File
@@ -1,5 +1,5 @@
import React from 'react'; 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 axios from 'axios'; // eslint-disable-line no-unused-vars
import { Link } from 'react-router-dom'; // 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"] }] */ /*eslint no-console: ["error", { allow: ["warn", "error", "info"] }] */
@@ -55,7 +55,6 @@ class Recent extends React.Component {
} }
render() { render() {
const { error, isLoaded, items } = this.state; const { error, isLoaded, items } = this.state;
if (error) { if (error) {
@@ -65,22 +64,20 @@ class Recent extends React.Component {
</React.Fragment> </React.Fragment>
); );
} else if (!isLoaded) { } else if (!isLoaded) {
return ( return <Col className="text-center">
<React.Fragment> <div className="lds-ellipsis"><div></div><div></div><div></div><div></div></div>
<Col> </Col>;
<p className="text-center">Loading...</p>
</Col>
</React.Fragment>
);
} else { } else {
if (window.innerWidth < 992) {
return ( return (
<React.Fragment> <React.Fragment>
{items.map(item => ( {items.map(item => (
<Col md="4"> <Col key={item.id} md="4">
<Card key={item.id}> <Card >
<Link <Link
to={{ to={{
pathname: '/video/' + item.id, pathname: '/video/' + item.id,
search: "?ref=Recent"
}} }}
> >
<Card.Img <Card.Img
@@ -90,7 +87,8 @@ class Recent extends React.Component {
<Card.ImgOverlay> <Card.ImgOverlay>
<Card.Title className="bg-dark d-inline text-white"> <Card.Title className="bg-dark d-inline text-white">
{item.name}<br /> {item.name}<br />
{item.lastSelected} <span>Ultima volta visto: {this.ISO_8601parse(item.lastWatched)} </span><br />
<span>Reccomender: Recent</span>
</Card.Title> </Card.Title>
</Card.ImgOverlay> </Card.ImgOverlay>
</Link> </Link>
@@ -99,7 +97,34 @@ class Recent extends React.Component {
</Col>))} </Col>))}
</React.Fragment> </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 React, { Component } from 'react';
import axios from 'axios'; import axios from 'axios';
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import {Card,Col} from "react-bootstrap"; import { Card, Col, Media } from "react-bootstrap";
import moment from "moment"; import moment from "moment";
@@ -62,6 +62,7 @@ class Related extends Component {
render() { render() {
const ISO_8601parse = this.ISO_8601parse; const ISO_8601parse = this.ISO_8601parse;
if (window.innerWidth < 992) {
return ( return (
<React.Fragment> <React.Fragment>
{this.state.items.map(function (item, index) { {this.state.items.map(function (item, index) {
@@ -71,6 +72,7 @@ class Related extends Component {
<Link <Link
to={{ to={{
pathname: '/video/' + item.id.videoId, pathname: '/video/' + item.id.videoId,
search: "?ref=Related"
}} }}
> >
<Card.Img <Card.Img
@@ -80,7 +82,8 @@ class Related extends Component {
<Card.ImgOverlay> <Card.ImgOverlay>
<Card.Title className="bg-dark d-inline text-white"> <Card.Title className="bg-dark d-inline text-white">
{item.snippet.title}<br /> {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.Title>
</Card.ImgOverlay> </Card.ImgOverlay>
</Link> </Link>
@@ -90,7 +93,34 @@ class Related extends Component {
})} })}
</React.Fragment> </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 = { Related.propTypes = {
+44 -9
View File
@@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import axios from 'axios'; import axios from 'axios';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { Card, Col } from 'react-bootstrap'; import { Col, Media, Card } from 'react-bootstrap';
class Search extends React.Component { class Search extends React.Component {
@@ -44,7 +44,8 @@ class Search extends React.Component {
// } // }
componentDidUpdate(prevProps, prevState) { 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())) 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', { axios.get('https://www.googleapis.com/youtube/v3/videos', {
params: { params: {
@@ -68,6 +69,8 @@ class Search extends React.Component {
) )
else else
this.youtubeSearch(); this.youtubeSearch();
}
} }
// componentWillUnmount() { // componentWillUnmount() {
@@ -102,15 +105,46 @@ class Search extends React.Component {
if (this.state.error) { if (this.state.error) {
return <React.Fragment>{this.state.error.message} -- {this.state.error.response.data.error.errors[0].reason} </React.Fragment>; return <React.Fragment>{this.state.error.message} -- {this.state.error.response.data.error.errors[0].reason} </React.Fragment>;
} else if (!this.state.isLoaded) { } 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{ }else{
return ( return (
<React.Fragment> <React.Fragment>
{this.state.res.items.map(item => (<Col key={item.id.videoId} md="4"> {this.state.res.items.map(item => (<Col md="4">
<Card> <Card key={item.id.videoId}>
<Link <Link
to={{ to={{
pathname: '/video/' + item.id.videoId, pathname: '/video/' + item.id.videoId,
search: "?ref=Search"
}} }}
> >
<Card.Img <Card.Img
@@ -119,16 +153,17 @@ class Search extends React.Component {
/> />
<Card.ImgOverlay> <Card.ImgOverlay>
<Card.Title className="bg-dark d-inline text-white"> <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.Title>
</Card.ImgOverlay> </Card.ImgOverlay>
</Link> </Link>
</Card> </Card>
</Col> </Col>))}
))}
</React.Fragment> </React.Fragment>
); );
} }}
} }
} }
+36 -9
View File
@@ -1,10 +1,9 @@
import React from 'react'; 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 axios from 'axios'; // eslint-disable-line no-unused-vars
import { Link } from 'react-router-dom'; // 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"] }] */ /*eslint no-console: ["error", { allow: ["warn", "error", "info"] }] */
class fvitali extends React.Component { class fvitali extends React.Component {
state = { state = {
error: null, error: null,
@@ -79,13 +78,12 @@ class fvitali extends React.Component {
); );
} else if (!isLoaded) { } else if (!isLoaded) {
return ( return (
<React.Fragment> <Col className="text-center">
<Col> <div className="lds-ellipsis"><div></div><div></div><div></div><div></div></div>
<p className="text-center">Loading...</p>
</Col> </Col>
</React.Fragment>
); );
} else { } else {
if (window.innerWidth < 992) {
return ( return (
<React.Fragment> <React.Fragment>
{items.map(item => (<Col md="4"> {items.map(item => (<Col md="4">
@@ -93,6 +91,7 @@ class fvitali extends React.Component {
<Link <Link
to={{ to={{
pathname: '/video/' + item.videoID, pathname: '/video/' + item.videoID,
search: "?ref=fvitali"
}} }}
> >
<Card.Img <Card.Img
@@ -101,16 +100,44 @@ class fvitali extends React.Component {
/> />
<Card.ImgOverlay> <Card.ImgOverlay>
<Card.Title className="bg-dark d-inline text-white"> <Card.Title className="bg-dark d-inline text-white">
{item.name}<br/> <span>{item.name}</span> <br/>
{item.lastSelected}
<span>Reccomender: fvitali</span>
</Card.Title> </Card.Title>
</Card.ImgOverlay> </Card.ImgOverlay>
</Link> </Link>
</Card> </Card>
</Col>))} </Col>))}
</React.Fragment> </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 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 axios from 'axios'; // eslint-disable-line no-unused-vars
import { Link } from 'react-router-dom'; // eslint-disable-line no-unused-vars import { Link } from 'react-router-dom'; // eslint-disable-line no-unused-vars
import moment from "moment"; import moment from "moment";
var _ = require('lodash');
class popGlobaleAssoluta extends React.Component { class popGlobaleAssoluta extends React.Component {
state = { state = {
@@ -13,70 +14,54 @@ class popGlobaleAssoluta extends React.Component {
}; };
componentDidMount() { componentDidMount() {
// listSiti.map( // 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'];
// sito => let listSiti = ['1828', '1838','1839', '1846', '1831', '1827', '1823', '1863', '1834', '1901'];//, '1859', '1841', '1905', '1864', '1860', '1858', '1913', '1855', '1912', '1915', '1854', '1910'];
// axios.get(`http://site${sito}.tw.cs.unibo.it/globpop`, { Promise.all(
// 'params': { listSiti.map(
// 'id': this.props.match.params.id el => fetch(`http://site${el}.tw.cs.unibo.it/globpop?id=${this.props.match.params.id}`)
// } .then(res =>
// }) res.json()
// )
// 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))
})
) )
)
).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 // METODI
getThumbnailsNames(reccomended) { 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', { axios.get('https://www.googleapis.com/youtube/v3/videos', {
params: { params: {
part: 'snippet', part: 'snippet',
id: idToLookFor.toString(), id: _.uniq(idToLookFor).slice(0,50).toString(),
key: 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig', key: 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig',
fields: 'items(id,snippet/thumbnails/medium,snippet/title)' fields: 'items(id,snippet/thumbnails/high,snippet/title)'
} }
}) })
.then( .then(
res1 => { 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({ this.setState({
items: res1.data.items,
isLoaded: true, isLoaded: true,
items: reccomended
}); });
console.log(res1)
}) })
} }
render() { render() {
const { error, isLoaded, items, headers } = this.state; const { error, isLoaded, items } = this.state;
if (error) { if (error) {
return ( return (
<React.Fragment> <React.Fragment>
@@ -91,7 +76,7 @@ class popGlobaleAssoluta extends React.Component {
</Col> </Col>
</React.Fragment> </React.Fragment>
); );
} else { } else { if (window.innerWidth < 992){
return ( return (
<React.Fragment> <React.Fragment>
{items.map(item => (<Col md="4"> {items.map(item => (<Col md="4">
@@ -99,16 +84,18 @@ class popGlobaleAssoluta extends React.Component {
<Link <Link
to={{ to={{
pathname: '/video/' + item.videoID, pathname: '/video/' + item.videoID,
search: "?ref=popGlobaleAssoluta"
}} }}
> >
<Card.Img <Card.Img
src={item.thumbnail} src={item.snippet.thumbnails.high.url}
alt={'Thumbnail of ' + item.name} alt={'Thumbnail of ' + item.snippet.title}
/> />
<Card.ImgOverlay> <Card.ImgOverlay>
<Card.Title className="bg-dark d-inline text-white"> <Card.Title className="bg-dark d-inline text-white">
{item.name}<br /> {item.snippet.title}<br />
{item.lastSelected} {item.snippet.channelTitle}<br />
<span>Reccomender: popGlobaleAssoluta</span>
</Card.Title> </Card.Title>
</Card.ImgOverlay> </Card.ImgOverlay>
</Link> </Link>
@@ -117,7 +104,34 @@ class popGlobaleAssoluta extends React.Component {
</React.Fragment> </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 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 axios from 'axios'; // eslint-disable-line no-unused-vars
import { Link } from 'react-router-dom'; // 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"] }] */ /*eslint no-console: ["error", { allow: ["warn", "error", "info"] }] */
@@ -18,13 +18,17 @@ class PopRelLoc extends React.Component {
} }
componentDidMount() { componentDidMount() {
let tmp = JSON.parse(localStorage.getItem('lastWatched')); axios.get("http://site1854.tw.cs.unibo.it/videotrack",{
let j=tmp.findIndex(el=>el.id === localStorage["lastId"]); params: {
//this.getThumbnailsNames(tmp[j].prevVideos); "prevId" : localStorage['lastId']
if (tmp.length === 0 || localStorage["prevId"] === '1') }
{this.getThumbnailsNames(JSON.parse(localStorage.getItem('first')))} }).then(res=>{
else this.getThumbnailsNames(res.data)
{this.getThumbnailsNames(tmp[j].prevVideos)} this.setState({
items : res.data
})
},
error=>console.error(error))
} }
@@ -80,6 +84,7 @@ class PopRelLoc extends React.Component {
</React.Fragment> </React.Fragment>
); );
} else { } else {
if (window.innerWidth < 992) {
return ( return (
<React.Fragment> <React.Fragment>
{items.map(item => ( {items.map(item => (
@@ -88,6 +93,7 @@ class PopRelLoc extends React.Component {
<Link <Link
to={{ to={{
pathname: '/video/' + item.id, pathname: '/video/' + item.id,
search: "?ref=popRelLoc"
}} }}
> >
<Card.Img <Card.Img
@@ -97,7 +103,8 @@ class PopRelLoc extends React.Component {
<Card.ImgOverlay> <Card.ImgOverlay>
<Card.Title className="bg-dark d-inline text-white"> <Card.Title className="bg-dark d-inline text-white">
{item.name}<br /> {item.name}<br />
{item.lastSelected} <span>Visto: {item.timesWatched} volt{item.timesWatched === 1 ?"a":"e"} </span><br />
<span> Reccomender: popRelLoc </span>
</Card.Title> </Card.Title>
</Card.ImgOverlay> </Card.ImgOverlay>
</Link> </Link>
@@ -106,7 +113,34 @@ class PopRelLoc extends React.Component {
</Col>))} </Col>))}
</React.Fragment> </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;