Archived
Compare commits
114
Commits
playeronside
...
layout1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8bf6ffe97f | ||
|
|
82b7997da8 | ||
|
|
4d5e96a0e8 | ||
|
|
233088fe5b | ||
|
|
a0ccb675a0 | ||
|
|
546396c7cc | ||
|
|
597ca1cca0 | ||
|
|
9c35961a7a | ||
|
|
82f3a01356 | ||
|
|
0bffa1094f | ||
|
|
a26b7fe72c | ||
|
|
a06540c03b | ||
|
|
6ba6caa03b | ||
|
|
846e06d588 | ||
|
|
0d28e4f5a6 | ||
|
|
8475cb4ca8 | ||
|
|
99c948f7b5 | ||
|
|
d9d6138fd9 | ||
|
|
12f375afed | ||
|
|
3a4a0e84c7 | ||
|
|
bb67bb1697 | ||
|
|
8af517b965 | ||
|
|
db8800965d | ||
|
|
668b259adb | ||
|
|
cb35dfbe65 | ||
|
|
d99f2fe057 | ||
|
|
41812bfb64 | ||
|
|
8ecd6ff76c | ||
|
|
815a713412 | ||
|
|
10d54b51e6 | ||
|
|
d6031d313b | ||
|
|
9032bc3f98 | ||
|
|
534d3c1b25 | ||
|
|
d847ab382d | ||
|
|
0e48971e1e | ||
|
|
5a88a201e7 | ||
|
|
d844fab282 | ||
|
|
1137e528e1 | ||
|
|
06800e51cd | ||
|
|
7fef149424 | ||
|
|
340bb46c46 | ||
|
|
70be1d815c | ||
|
|
0340f45cd7 | ||
|
|
a4752a42da | ||
|
|
aabf86e3d7 | ||
|
|
5f86943496 | ||
|
|
52d9ac8602 | ||
|
|
2466c9798d | ||
|
|
0eaa8eb805 | ||
|
|
6e2a6c84df | ||
|
|
8057a99947 | ||
|
|
61d113fd14 | ||
|
|
c28618dc51 | ||
|
|
e162300121 | ||
|
|
746c239f03 | ||
|
|
bd55d431e8 | ||
|
|
6c766c3c33 | ||
|
|
f72ad098f9 | ||
|
|
1d008dc41a | ||
|
|
f0351615b7 | ||
|
|
36932c5c3c | ||
|
|
1c3a5b3409 | ||
|
|
c01fe3daf7 | ||
|
|
e3970731be | ||
|
|
108d4b72ee | ||
|
|
c60f4b9323 | ||
|
|
e32739efe2 | ||
|
|
4e76a809e1 | ||
|
|
18b0dbcc39 | ||
|
|
dab303c617 | ||
|
|
146e59fbed | ||
|
|
e624b3a7f7 | ||
|
|
5ae00f9237 | ||
|
|
407a6c18cc | ||
|
|
8ca65fed00 | ||
|
|
4e906261be | ||
|
|
4631fa7ec2 | ||
|
|
4ac7f80d2f | ||
|
|
b24efcc18b | ||
|
|
ccde79f4c4 | ||
|
|
d0ce052bc4 | ||
|
|
aa575bc9cc | ||
|
|
232c33cab8 | ||
|
|
ca17c2d73b | ||
|
|
ab1b13ec14 | ||
|
|
a981178104 | ||
|
|
c3b7c22119 | ||
|
|
fd25da5bed | ||
|
|
aa425c1689 | ||
|
|
242effb4c8 | ||
|
|
f952c66316 | ||
|
|
228e96a114 | ||
|
|
49cdcfeb74 | ||
|
|
323adb209b | ||
|
|
3c84183b5f | ||
|
|
7d94fb34ca | ||
|
|
ab13120448 | ||
|
|
36c9c26089 | ||
|
|
c1c69d0797 | ||
|
|
6f8d7d506a | ||
|
|
fcb54b629a | ||
|
|
8f70e3627e | ||
|
|
e57b90f54c | ||
|
|
1b022cc4b3 | ||
|
|
c7b4f0c347 | ||
|
|
9eca8afd9a | ||
|
|
a7edfd9ee5 | ||
|
|
a554b26ccb | ||
|
|
a0f8689baa | ||
|
|
3110e36b4f | ||
|
|
2b58b105dd | ||
|
|
b0dbba7673 | ||
|
|
ea18c64925 | ||
|
|
2bca56b881 |
@@ -17,9 +17,12 @@
|
|||||||
.env.development.local
|
.env.development.local
|
||||||
.env.test.local
|
.env.test.local
|
||||||
.env.production.local
|
.env.production.local
|
||||||
|
.env
|
||||||
|
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
|
|
||||||
.idea/
|
.idea/
|
||||||
|
.vs/
|
||||||
|
db.json
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig
|
'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig'
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
{
|
|
||||||
"videos": [
|
|
||||||
{
|
|
||||||
"id": "cu3K1njbYqs",
|
|
||||||
"timesWatched": 1,
|
|
||||||
"lastWatched": "2018-12-02T20:43:18.202Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "PoSbnAFvqfA",
|
|
||||||
"timesWatched": 1,
|
|
||||||
"lastWatched": "2018-12-02T20:43:24.851Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "rzeLynj1GYM",
|
|
||||||
"timesWatched": 2,
|
|
||||||
"lastWatched": "2018-12-02T20:43:45.916Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "0J2QdDbelmY",
|
|
||||||
"timesWatched": 1,
|
|
||||||
"lastWatched": "2018-12-02T20:49:32.498Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "unRjK82bDLw",
|
|
||||||
"timesWatched": 2,
|
|
||||||
"lastWatched": "2018-12-02T20:49:50.769Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "g2N0TkfrQhY",
|
|
||||||
"timesWatched": 1,
|
|
||||||
"lastWatched": "2018-12-02T20:52:07.780Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "EM4vblG6BVQ",
|
|
||||||
"timesWatched": 1,
|
|
||||||
"lastWatched": "2018-12-02T20:52:43.282Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "tPwqOWK6EFw",
|
|
||||||
"timesWatched": 1,
|
|
||||||
"lastWatched": "2018-12-02T20:53:26.049Z"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
process.env['NODE_ENV'] = 'production';
|
||||||
|
const express = require('express');
|
||||||
|
const compression = require('compression')
|
||||||
|
const bodyParser = require('body-parser');
|
||||||
|
const low = require('lowdb');
|
||||||
|
const lodashId = require('lodash-id');
|
||||||
|
const FileAsync = require('lowdb/adapters/FileAsync');
|
||||||
|
const app = express(); // app is an instance of express
|
||||||
|
|
||||||
|
app.use(compression()); // enables gzip compression
|
||||||
|
app.use(bodyParser.urlencoded({ extended: false })) // parse application/x-www-form-urlencoded
|
||||||
|
app.use(bodyParser.json()) // parse application/json
|
||||||
|
|
||||||
|
|
||||||
|
// Create database instance and start server
|
||||||
|
// const adapter = new FileAsync(__dirname + '/db.json');
|
||||||
|
low(new FileAsync(__dirname + '/db.json')) // production
|
||||||
|
.then(db => {
|
||||||
|
db._.mixin(lodashId);
|
||||||
|
// DATABASE ROUTES
|
||||||
|
|
||||||
|
// ==============
|
||||||
|
|
||||||
|
app.post('/test', (req, res) => {
|
||||||
|
// "reason": {
|
||||||
|
// "fitali": req.body.reason.toString() === "fvitali" ? 1:0,
|
||||||
|
// "": req.body.reason.toString() === "" ? 1:0,
|
||||||
|
// "": req.body.reason.toString() === "" ? 1:0,
|
||||||
|
// }
|
||||||
|
// try {
|
||||||
|
// let test = table.updateById(req.body.id, { })
|
||||||
|
// }
|
||||||
|
// catch(e) {
|
||||||
|
// }
|
||||||
|
res.send(req.body);
|
||||||
|
});
|
||||||
|
|
||||||
|
// ==============
|
||||||
|
|
||||||
|
// GET /globpop
|
||||||
|
app.get('/globpop', (req, res) => {
|
||||||
|
req.query.id ? res.send(req.query.id) : res.status(400).send('Bad Request');
|
||||||
|
});
|
||||||
|
|
||||||
|
// OPTIONS /videotrack
|
||||||
|
app.options('/videotrack', (req, res) => {
|
||||||
|
res.set({
|
||||||
|
'Access-Control-Allow-Origin': '*',
|
||||||
|
'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
|
||||||
|
'Access-Control-Allow-Headers': 'Content-Type',
|
||||||
|
'Access-Control-Max-Age': 600
|
||||||
|
})
|
||||||
|
res.status(200).end();
|
||||||
|
})
|
||||||
|
|
||||||
|
// GET /videotrack
|
||||||
|
app.get('/videotrack', (req, res) => {
|
||||||
|
const videos = db.get('videos');
|
||||||
|
req.query.id ? res.send(videos.getById(req.query.id).value()) : res.send(videos.value())
|
||||||
|
});
|
||||||
|
|
||||||
|
// POST /videotrack
|
||||||
|
app.post('/videotrack', (req, res) => {
|
||||||
|
const videos = db.get('videos');
|
||||||
|
const row = videos.getById(req.body.id);
|
||||||
|
if (row.value()) {
|
||||||
|
row
|
||||||
|
.update('timesWatched', (n) => ++n)
|
||||||
|
.update('lastWatched', () => new Date().toISOString())
|
||||||
|
.write()
|
||||||
|
.then(output => res.send(output))
|
||||||
|
} else {
|
||||||
|
let newRow = {
|
||||||
|
"id": req.body.id.toString(),
|
||||||
|
"timesWatched": 1,
|
||||||
|
"lastWatched": new Date().toISOString(),
|
||||||
|
}
|
||||||
|
videos.push(newRow).last().write().then(output => res.send(output))
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set db default values
|
||||||
|
return db.defaults({ videos: [] }).write();
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
app.listen(8000, () => console.log('listen on 8000')); // bind to port 8000 as required from specs
|
||||||
|
});
|
||||||
+141
-14
@@ -1,25 +1,34 @@
|
|||||||
|
process.env['NODE_ENV'] = 'production';
|
||||||
|
//'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig' = 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig';
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
|
const compression = require('compression')
|
||||||
const bodyParser = require('body-parser');
|
const bodyParser = require('body-parser');
|
||||||
const low = require('lowdb');
|
const low = require('lowdb');
|
||||||
const lodashId = require('lodash-id');
|
const lodashId = require('lodash-id');
|
||||||
const FileAsync = require('lowdb/adapters/FileAsync');
|
const FileAsync = require('lowdb/adapters/FileAsync');
|
||||||
const app = express(); // app is an instance of express
|
const app = express(); // app is an instance of express
|
||||||
|
|
||||||
|
app.use(compression()); // enables gzip compression
|
||||||
app.use(bodyParser.urlencoded({ extended: false })) // parse application/x-www-form-urlencoded
|
app.use(bodyParser.urlencoded({ extended: false })) // parse application/x-www-form-urlencoded
|
||||||
app.use(bodyParser.json()) // parse application/json
|
app.use(bodyParser.json()) // parse application/json
|
||||||
app.use(express.static(__dirname + '/build')); // serve static build site
|
|
||||||
|
|
||||||
|
app.get('/a', (req, res) => {
|
||||||
|
res.send(process.env);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// Create database instance and start server
|
// Create database instance and start server
|
||||||
// const adapter = new FileAsync(__dirname + '/db.json');
|
// const adapter = new FileAsync(__dirname + '/db.json');
|
||||||
low(new FileAsync(__dirname + '/db.json')) // production
|
low(new FileAsync(__dirname + '/db.json')) // production
|
||||||
// low(new FileAsync('/tmp/db.json')) // dev
|
|
||||||
.then(db => {
|
.then(db => {
|
||||||
db._.mixin(lodashId);
|
db._.mixin(lodashId);
|
||||||
// DATABASE ROUTES
|
// DATABASE ROUTES
|
||||||
|
|
||||||
// ==============
|
// ==============
|
||||||
|
|
||||||
app.post('/test',(req,res)=>{
|
app.post('/test', (req, res) => {
|
||||||
// "reason": {
|
// "reason": {
|
||||||
// "fitali": req.body.reason.toString() === "fvitali" ? 1:0,
|
// "fitali": req.body.reason.toString() === "fvitali" ? 1:0,
|
||||||
// "": req.body.reason.toString() === "" ? 1:0,
|
// "": req.body.reason.toString() === "" ? 1:0,
|
||||||
@@ -33,31 +42,145 @@ low(new FileAsync(__dirname + '/db.json')) // production
|
|||||||
res.send(req.body);
|
res.send(req.body);
|
||||||
});
|
});
|
||||||
|
|
||||||
// ==============
|
// ==============
|
||||||
|
// 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 /videotrack/:id?
|
// GET /globpop
|
||||||
app.get('/videotrack/:id?', (req, res) => {
|
app.get('/globpop', (req, res) => {
|
||||||
const videos = db.get('videos');
|
res.set({
|
||||||
req.params.id ? res.send(videos.getById(req.params.id).value()) : res.send(videos.value())
|
'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
|
||||||
|
app.options('/videotrack', (req, res) => {
|
||||||
|
res.set({
|
||||||
|
'Access-Control-Allow-Origin': '*',
|
||||||
|
'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
|
||||||
|
'Access-Control-Allow-Headers': 'Content-Type',
|
||||||
|
'Access-Control-Max-Age': 600
|
||||||
|
})
|
||||||
|
res.status(200).end();
|
||||||
|
})
|
||||||
|
|
||||||
|
// GET /videotrack
|
||||||
|
app.get('/videotrack', (req, res) => {
|
||||||
|
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
|
// POST /videotrack
|
||||||
app.post('/videotrack', (req, res) => {
|
app.post('/videotrack', (req, res) => {
|
||||||
|
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 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(output))
|
videos.push(newRow).last().write().then(output => res.send(200, output))
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -65,5 +188,9 @@ low(new FileAsync(__dirname + '/db.json')) // production
|
|||||||
return db.defaults({ videos: [] }).write();
|
return db.defaults({ videos: [] }).write();
|
||||||
})
|
})
|
||||||
.then(() => {
|
.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
|
app.listen(8000, () => console.log('listen on 8000')); // bind to port 8000 as required from specs
|
||||||
});
|
});
|
||||||
|
|||||||
Generated
+4029
-754
File diff suppressed because it is too large
Load Diff
+10
-3
@@ -1,16 +1,21 @@
|
|||||||
{
|
{
|
||||||
"name": "hazetv-alfatube-1",
|
"name": "hazetv-alfatube-1",
|
||||||
"version": "0.1.0",
|
"version": "0.1.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@c0b41/ytclear": "^1.0.0",
|
||||||
"axios": "latest",
|
"axios": "latest",
|
||||||
"body-parser": "^1.18.3",
|
"body-parser": "^1.18.3",
|
||||||
"bootstrap": "^4.1.3",
|
"bootstrap": "^4.1.3",
|
||||||
|
"compression": "^1.7.3",
|
||||||
|
"dotenv": "^6.2.0",
|
||||||
"express": "^4.16.4",
|
"express": "^4.16.4",
|
||||||
|
"get-artist-title": "^1.1.1",
|
||||||
"lodash-id": "^0.14.0",
|
"lodash-id": "^0.14.0",
|
||||||
"lowdb": "^1.0.0",
|
"lowdb": "^1.0.0",
|
||||||
"moment": "^2.23.0",
|
"moment": "^2.23.0",
|
||||||
"moment-duration-format": "^2.2.2",
|
"moment-duration-format": "^2.2.2",
|
||||||
|
"node-sass": "^4.11.0",
|
||||||
"react": "^16.6.1",
|
"react": "^16.6.1",
|
||||||
"react-app-polyfill": "^0.1.3",
|
"react-app-polyfill": "^0.1.3",
|
||||||
"react-bootstrap": "^1.0.0-beta.2",
|
"react-bootstrap": "^1.0.0-beta.2",
|
||||||
@@ -18,14 +23,16 @@
|
|||||||
"react-height": "^3.0.0",
|
"react-height": "^3.0.0",
|
||||||
"react-linkify": "^0.2.2",
|
"react-linkify": "^0.2.2",
|
||||||
"react-router-dom": "^4.3.1",
|
"react-router-dom": "^4.3.1",
|
||||||
"react-scripts": "2.1.1",
|
"react-scripts": "^2.1.3",
|
||||||
"react-youtube": "^7.8.0",
|
"react-youtube": "^7.8.0",
|
||||||
|
"wikidata-sdk": "^5.15.9",
|
||||||
"wikijs": "^4.8.1",
|
"wikijs": "^4.8.1",
|
||||||
"youtube-page-token": "^1.0.1"
|
"youtube-page-token": "^1.0.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start",
|
"start": "react-scripts start",
|
||||||
"build": "react-scripts build",
|
"build": "react-scripts build",
|
||||||
|
"build2": "GENERATE_SOURCEMAP=false react-scripts build",
|
||||||
"test": "react-scripts test",
|
"test": "react-scripts test",
|
||||||
"node": "npm run build && node ./node-entry.js",
|
"node": "npm run build && node ./node-entry.js",
|
||||||
"eject": "react-scripts eject"
|
"eject": "react-scripts eject"
|
||||||
@@ -36,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.
|
After Width: | Height: | Size: 74 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 88 KiB |
+1
-1
@@ -19,7 +19,7 @@
|
|||||||
work correctly both with client-side routing and a non-root public URL.
|
work correctly both with client-side routing and a non-root public URL.
|
||||||
Learn how to configure a non-root public URL by running `npm run build`.
|
Learn how to configure a non-root public URL by running `npm run build`.
|
||||||
-->
|
-->
|
||||||
<title>react-4</title>
|
<title>HazeTv</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>
|
<noscript>
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import React, { Component } from 'react'
|
||||||
|
import { Container, Row, Col, Image } from 'react-bootstrap';
|
||||||
|
import './css/AboutUs.css';
|
||||||
|
|
||||||
|
export default class AboutUs extends Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Container>
|
||||||
|
<Row className="show-Container text-center">
|
||||||
|
<Col xs={12} sm={4} className="person-wrapper">
|
||||||
|
<Image src="assets/person-1.jpg" roundedCircle className="profile-pic" />
|
||||||
|
<h3>Matteo Scorzafava</h3>
|
||||||
|
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>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>Recommender Recent<br/>
|
||||||
|
Recommender fvitali<br/>
|
||||||
|
Gestione della barra dei recommender<br/>
|
||||||
|
AboutUs <br/>
|
||||||
|
Recommender similarityArtist
|
||||||
|
</p>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Container>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
+62
-27
@@ -1,51 +1,82 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Route, Switch } from 'react-router-dom';
|
import { Route, Switch, withRouter, matchPath } from 'react-router-dom';
|
||||||
import 'bootstrap/dist/css/bootstrap.css';
|
|
||||||
import { Row, Col, Button, Collapse } from 'react-bootstrap';
|
import { Row, Col, Button, Collapse } from 'react-bootstrap';
|
||||||
import TopBar from './TopBar';
|
import TopBar from './TopBar';
|
||||||
import VideoPlayer from './VideoPlayer';
|
import VideoPlayer from './VideoPlayer';
|
||||||
import VideoInfo from './VideoInfo';
|
import VideoInfo from './VideoInfo';
|
||||||
import VideoList from './VideoList';
|
import VideoList from './VideoList';
|
||||||
import Suggestion from './areainfo/Suggestion';
|
import Suggestion from './Suggestion';
|
||||||
|
import AboutUs from './AboutUs';
|
||||||
import { ReactHeight } from 'react-height';
|
import { ReactHeight } from 'react-height';
|
||||||
import './css/App.css';
|
import './css/App.css';
|
||||||
|
|
||||||
|
|
||||||
class App extends React.Component {
|
class App extends React.Component {
|
||||||
constructor(props) {
|
state = {
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
playerHeight: null,
|
playerHeight: null,
|
||||||
navHeight: null,
|
navHeight: null,
|
||||||
blackbgHeight: null,
|
blackbgHeight: null,
|
||||||
isInfoToggled: false
|
isInfoToggled: false,
|
||||||
|
videoId: localStorage['lastId']
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
// componentDidMount() {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// componentDidUpdate(prevProps, prevState) {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
static getDerivedStateFromProps(nextProps, prevState) {
|
||||||
|
let idMatch = matchPath(nextProps.location.pathname, {
|
||||||
|
path: "/video/:id/:rec?",
|
||||||
|
exact: true,
|
||||||
|
strict: false
|
||||||
|
});
|
||||||
|
if (idMatch && idMatch.params.id !== prevState.videoId) {
|
||||||
|
localStorage.setItem('prevId', prevState.videoId)
|
||||||
|
localStorage.setItem('lastId', idMatch.params.id)
|
||||||
|
return { videoId: idMatch.params.id };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
render() {
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<ReactHeight className="row" onHeightReady={height => { this.setState({ navHeight: height }); console.log('l', height) }}>
|
<Row id="top">
|
||||||
<TopBar />
|
<TopBar />
|
||||||
</ReactHeight>
|
</Row>
|
||||||
<ReactHeight onHeightReady={height => this.setState({ blackbgHeight: height })} className="row upperSection p-2" >
|
<Row className="upperSection">
|
||||||
<Col
|
<Col
|
||||||
xs="12"
|
xs="12"
|
||||||
lg={this.state.isInfoToggled ? { span: 6, offset: 1, 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">
|
||||||
<ReactHeight onHeightReady={height => this.setState({ playerHeight: height })}>
|
<Col xs="12" lg={this.state.isInfoToggled ? { span: 10, offset: 1 } : { span: 10, offset: 1 }}>
|
||||||
<Route path={["/video/:id", "/*"]} component={VideoPlayer} /> {/* change component to children */}
|
<ReactHeight onHeightReady={height => { this.setState({ playerHeight: height }) }}>
|
||||||
|
<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-sm-0"
|
className={this.state.isInfoToggled ? "" : "blackBg"}
|
||||||
style={{ 'overflow': "auto", 'max-height': this.state.playerHeight }} >
|
style={window.innerWidth < 992 ?
|
||||||
<div class="d-flex justify-content-center">
|
{ 'overflow': "auto", 'display': 'fixed', 'maxHeight': this.state.playerHeight * 1.4 + 'px' } :
|
||||||
|
{ 'overflow': "auto", 'maxHeight': `${this.state.playerHeight}px` }}>
|
||||||
|
{/* true = style for xs ;; false = style for lg */}
|
||||||
|
<div className="d-flex justify-content-center">
|
||||||
<Button
|
<Button
|
||||||
variant="outline-light"
|
variant="outline-light"
|
||||||
onClick={() => this.setState({ isInfoToggled: !this.state.isInfoToggled })}
|
onClick={() => this.setState({ isInfoToggled: !this.state.isInfoToggled, dirtyBg: true })}
|
||||||
className="w-50 pt-1 align-content-center"
|
className="pt-1 "
|
||||||
aria-controls="infovideo-collapse"
|
aria-controls="infovideo-collapse"
|
||||||
aria-expanded={this.state.isInfoToggled}>
|
aria-expanded={this.state.isInfoToggled}>
|
||||||
{this.state.isInfoToggled ? "Nascondi informazioni" : "Mostra informazioni"}
|
{this.state.isInfoToggled ? "Nascondi informazioni" : "Mostra informazioni"}
|
||||||
@@ -53,21 +84,25 @@ render() {
|
|||||||
</div>
|
</div>
|
||||||
<Collapse in={this.state.isInfoToggled}>
|
<Collapse in={this.state.isInfoToggled}>
|
||||||
<div className="pt-1" id="infovideo-collapse">
|
<div className="pt-1" id="infovideo-collapse">
|
||||||
<Route path={["/video/:id", "/search/:query", "/"]} component={VideoInfo} />
|
<Route render={(props) => <VideoInfo {...props} key={this.state.videoId} videoId={this.state.videoId} />} />
|
||||||
</div>
|
</div>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
</Col>
|
</Col>
|
||||||
</ReactHeight>
|
</Row>
|
||||||
<Row style={{ "max-height": `calc(99vh - ${this.state.blackbgHeight}px - ${this.state.navHeight}px)` }} 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", "/search/:query"]} component={Suggestion} />
|
<Route path={"/video/:id"} component={Suggestion} />
|
||||||
|
<Route path={"/search/:query"} component={Suggestion} />
|
||||||
<Route render={() => <div>URL not found</div>} />
|
<Route render={() => <div>URL not found</div>} />
|
||||||
</Switch>
|
</Switch>
|
||||||
</Row>
|
</Row>
|
||||||
|
<Row id="AboutUs">
|
||||||
|
<Route exact path="/" component={AboutUs} />
|
||||||
|
</Row>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App;
|
export default withRouter(App);
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import { Switch, Route } from 'react-router';
|
||||||
|
import Random from './reccomenders/Random';
|
||||||
|
import Related from './reccomenders/Related';
|
||||||
|
import Search from './reccomenders/Search';
|
||||||
|
import fvitali from './reccomenders/fvitali';
|
||||||
|
import popGlobaleAssoluta from './reccomenders/popGlobaleAssoluta';
|
||||||
|
import Recent from './reccomenders/Recent';
|
||||||
|
import similarityArtist from './reccomenders/similarityArtist';
|
||||||
|
import popLocaleAss from './reccomenders/popLocaleAss';
|
||||||
|
import PopRelLoc from './reccomenders/popRelLoc';
|
||||||
|
import genreSimilarity from './reccomenders/genreSimilarity';
|
||||||
|
|
||||||
|
// and so on..
|
||||||
|
|
||||||
|
class Suggestion extends Component {
|
||||||
|
|
||||||
|
// static getDerivedStateFromProps(nextProps, prevState) {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// componentDidMount() {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// shouldComponentUpdate(nextProps, nextState) {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// componentDidUpdate(prevProps, prevState) {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// componentWillUnmount() {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<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>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Suggestion;
|
||||||
+41
-31
@@ -3,60 +3,70 @@ import {
|
|||||||
Navbar,
|
Navbar,
|
||||||
Nav,
|
Nav,
|
||||||
NavDropdown,
|
NavDropdown,
|
||||||
//Form,
|
|
||||||
FormControl,
|
FormControl,
|
||||||
Button
|
Button
|
||||||
} from 'react-bootstrap'; //eslint-disable-next-line
|
} from 'react-bootstrap'; //eslint-disable-next-line
|
||||||
import { Link, withRouter } from 'react-router-dom';
|
import { Link, withRouter } from 'react-router-dom';
|
||||||
import './css/TopBar.css';
|
import './css/TopBar.css';
|
||||||
// import PropTypes from "prop-types";
|
|
||||||
|
|
||||||
|
|
||||||
class TopBar extends Component {
|
class TopBar extends Component {
|
||||||
constructor(props) {
|
state = {
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
query: ''
|
query: ''
|
||||||
};
|
};
|
||||||
this.handleChange = this.handleChange.bind(this);
|
handleChange = event => {
|
||||||
this.handleSubmit = this.handleSubmit.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleChange(event) {
|
|
||||||
this.setState({
|
this.setState({
|
||||||
query: event.target.value
|
query: event.target.value
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
handleSubmit(event) {
|
handleSubmit = event => {
|
||||||
//alert(this.state.query);
|
|
||||||
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">
|
||||||
<Nav className="mr-auto">
|
<Nav className="mr-auto">
|
||||||
<Link to="/" className="text-light nav-link">Home</Link>
|
<Link to="/" className="text-light nav-link">Home</Link>
|
||||||
<Link to="/link" className="text-light nav-link">link</Link>
|
<Link to={{ pathname: `/video/${localStorage['lastId']}/vitali` }} className="text-light nav-link">Vitali</Link>
|
||||||
{/* <NavDropdown title="arnaldo" id="basic-nav-dropdown" >
|
<Link to={{ pathname: `/video/${localStorage['lastId']}/recent` }} className="text-light nav-link">Recent</Link>
|
||||||
<NavDropdown.Item href="#action/3.1">Action</NavDropdown.Item>
|
<Link to={{ pathname: `/video/${localStorage['lastId']}/random` }} className="text-light nav-link">Random</Link>
|
||||||
<NavDropdown.Item href="#action/3.2">
|
<Link to={{ pathname: `/video/${localStorage['lastId']}/related` }} className="text-light nav-link">Related</Link>
|
||||||
Another action
|
{<NavDropdown title="Similarity" id="basic-nav-dropdown" >
|
||||||
</NavDropdown.Item>
|
|
||||||
<NavDropdown.Item href="#action/3.3">
|
<Link to={{ pathname: `/video/${localStorage['lastId']}/similarityArtist` }} className="text-light nav-link">
|
||||||
Something
|
Artist
|
||||||
</NavDropdown.Item>
|
</Link>
|
||||||
<NavDropdown.Divider />
|
|
||||||
<NavDropdown.Item href="#action/3.4">
|
|
||||||
Separated link
|
<Link to={{ pathname: `/video/${localStorage['lastId']}/genreSimilarity` }} className="text-light nav-link">
|
||||||
</NavDropdown.Item>
|
Genre
|
||||||
</NavDropdown> */}
|
</Link>
|
||||||
|
|
||||||
|
</NavDropdown>}
|
||||||
|
{<NavDropdown title="Popolarità locale" id="basic-nav-dropdown" >
|
||||||
|
|
||||||
|
<Link to={{ pathname: `/video/${localStorage['lastId']}/popLocaleAss` }} className="text-light nav-link">
|
||||||
|
Assoluta
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
|
||||||
|
<Link to={{ pathname: `/video/${localStorage['lastId']}/popRelLoc` }} className="text-light nav-link">
|
||||||
|
Relativa
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
</NavDropdown>}
|
||||||
|
|
||||||
|
<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}>
|
||||||
<FormControl
|
<FormControl
|
||||||
@@ -65,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>
|
||||||
|
|||||||
+74
-186
@@ -1,256 +1,144 @@
|
|||||||
import React, { Component } from 'react';
|
import React from 'react';
|
||||||
import Wikipedia from './areainfo/Wikipedia';
|
import Wikipedia from './Wikipedia';
|
||||||
import { Col, Tabs, Tab,} from 'react-bootstrap';
|
import { Card, Tabs, Tab } from 'react-bootstrap';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import Linkify from "react-linkify";
|
import Linkify from "react-linkify";
|
||||||
import Card from "react-bootstrap/lib/Card";
|
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import momentDurationFormat from 'moment-duration-format';
|
import momentDurationFormat from 'moment-duration-format'; //eslint-disable-line no-unused-vars
|
||||||
|
import './css/VideoInfo.scss';
|
||||||
|
const ytclear = require('@c0b41/ytclear');
|
||||||
|
|
||||||
class VideoInfo extends Component {
|
class VideoInfo extends React.Component {
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
state = {
|
||||||
this.state = {
|
|
||||||
error: null,
|
error: null,
|
||||||
isLoaded: false,
|
isLoaded: false,
|
||||||
VideoDetails: {},
|
VideoDetails: {},
|
||||||
videoId: '0J2QdDbelmY',
|
videoId: '',
|
||||||
comments: []
|
comments: [],
|
||||||
|
others: {}
|
||||||
};
|
};
|
||||||
this.momentDuration = this.momentDuration.bind(this);
|
|
||||||
|
momentDuration(duration) {
|
||||||
|
return moment.duration(duration).format('hh:mm:ss')
|
||||||
}
|
}
|
||||||
|
|
||||||
momentDuration(duration){
|
ISO_8601parse(a) {
|
||||||
return moment.duration(duration).format('hh:mm:ss');
|
return moment(a, moment.ISO_8601).format('ddd, DD/MM/YYYY hh:mm:ss');
|
||||||
}
|
}
|
||||||
|
|
||||||
// componentWillMount() {
|
|
||||||
// if (this.props.match.params.id) {
|
|
||||||
// if (this.props.match.params.id === this.state.videoId) { }
|
|
||||||
// else {
|
|
||||||
// this.setState({ videoId: this.props.match.params.id });
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
console.log('didmount',this.state.videoId)
|
return axios.all([
|
||||||
axios.all([
|
|
||||||
axios.get('https://www.googleapis.com/youtube/v3/videos', { //Richiesta per tutte le info sul video
|
axios.get('https://www.googleapis.com/youtube/v3/videos', { //Richiesta per tutte le info sul video
|
||||||
params: {
|
params: {
|
||||||
'part': 'snippet,contentDetails,statistics,topicDetails',
|
'part': 'snippet,contentDetails,statistics,topicDetails',
|
||||||
'id': this.state.videoId,
|
'id': this.props.videoId,
|
||||||
'key': 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig'
|
'key': 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig' // 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig' in production
|
||||||
}
|
}
|
||||||
}), axios.get('https://www.googleapis.com/youtube/v3/commentThreads', { //Richiesta per ottenere i commenti del video
|
}), axios.get('https://www.googleapis.com/youtube/v3/commentThreads', { //Richiesta per ottenere i commenti del video
|
||||||
params: {
|
params: {
|
||||||
'part': 'snippet',
|
'part': 'snippet',
|
||||||
'videoId': this.state.videoId,
|
'videoId': this.props.videoId,
|
||||||
'order': 'relevance',
|
'order': 'relevance',
|
||||||
'key': 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig'
|
'key': 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig' // 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig' in production
|
||||||
}
|
}
|
||||||
})])
|
})])
|
||||||
.then(axios.spread((videosResponse, commentThreadResponse) => {
|
.then(axios.spread((videosResponse, commentThreadResponse) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
VideoDetails: videosResponse.data.items,
|
VideoDetails: videosResponse.data.items[0],
|
||||||
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
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps, prevState, snapshot) {
|
|
||||||
console.info('didup', this.props.match.params.id)
|
|
||||||
// this.setState((state, props) => { return { }});
|
|
||||||
if (this.props.match.params.id && !(prevProps.match.params.id === this.props.match.params.id)) {
|
|
||||||
this.setState({ videoId: this.props.match.params.id, isLoaded: false });
|
|
||||||
axios.all([
|
|
||||||
axios.get('https://www.googleapis.com/youtube/v3/videos', { //Richiesta per tutte le info sul video
|
|
||||||
params: {
|
|
||||||
'part': 'snippet,contentDetails,statistics,topicDetails',
|
|
||||||
'id': this.props.match.params.id,
|
|
||||||
'key': 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig'
|
|
||||||
}
|
|
||||||
}), axios.get('https://www.googleapis.com/youtube/v3/commentThreads', { //Richiesta per ottenere i commenti del video
|
|
||||||
params: {
|
|
||||||
'part': 'snippet',
|
|
||||||
'videoId': this.props.match.params.id,
|
|
||||||
'order': 'relevance',
|
|
||||||
'key': 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig'
|
|
||||||
}
|
|
||||||
})])
|
|
||||||
.then(axios.spread((videosResponse, commentThreadResponse) => {
|
|
||||||
this.setState({
|
|
||||||
VideoDetails: videosResponse.data.items,
|
|
||||||
comments: commentThreadResponse.data.items,
|
|
||||||
isLoaded: true
|
isLoaded: true
|
||||||
});
|
});
|
||||||
}), error => {
|
|
||||||
console.error(error);
|
|
||||||
this.setState({
|
|
||||||
isLoaded: true,
|
|
||||||
error
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// shouldComponentUpdate(nextProps, nextState){
|
|
||||||
// console.log('shouldup', nextProps, nextState)
|
|
||||||
// if(nextProps.match.params.id)
|
|
||||||
// return console.log('a',!(nextProps.match.params.id === this.state.videoId)) && !(nextProps.match.params.id === this.state.videoId) ;
|
|
||||||
// else if(!(nextState.videoId === this.state.videoId))
|
|
||||||
// return console.log('b') && true;
|
|
||||||
// else if(nextState.isLoaded)
|
|
||||||
// return console.log('d') && true;
|
|
||||||
// else
|
|
||||||
// return console.log('c') && false;
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
// componentWillReceiveProps(nextProps){
|
|
||||||
// if (nextProps.match.params.id === this.state.videoId) { console.log('1',nextProps)}
|
|
||||||
// else if (nextProps.match.params.id) {
|
|
||||||
// console.log('2',nextProps)
|
|
||||||
// this.setState({ videoId: nextProps.match.params.id });
|
|
||||||
// axios.all([
|
|
||||||
// axios.get('https://www.googleapis.com/youtube/v3/videos', { //Richiesta per tutte le info sul video
|
|
||||||
// params: {
|
|
||||||
// 'part': 'snippet,contentDetails,statistics,topicDetails',
|
|
||||||
// 'id': nextProps.match.params.id,
|
|
||||||
// 'key': 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig'
|
|
||||||
// }
|
|
||||||
// }), axios.get('https://www.googleapis.com/youtube/v3/commentThreads', { //Richiesta per ottenere i commenti del video
|
|
||||||
// params: {
|
|
||||||
// 'part': 'snippet',
|
|
||||||
// 'videoId': nextProps.match.params.id,
|
|
||||||
// 'order': 'relevance',
|
|
||||||
// 'key': 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig'
|
|
||||||
// }
|
|
||||||
// })])
|
|
||||||
// .then(axios.spread((videosResponse, commentThreadResponse) => {
|
|
||||||
// this.setState({
|
|
||||||
// VideoDetails: videosResponse.data.items,
|
|
||||||
// comments: commentThreadResponse.data.items,
|
|
||||||
// isLoaded: true
|
|
||||||
// });
|
|
||||||
// }), error => {
|
|
||||||
// console.error(error);
|
|
||||||
// this.setState({
|
|
||||||
// isLoaded: true,
|
|
||||||
// error
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// else{
|
|
||||||
// console.log('3',nextProps)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { error, isLoaded, VideoDetails, comments } = this.state;
|
const { error, isLoaded, VideoDetails, comments } = this.state;
|
||||||
const momentDuration = this.momentDuration; // bind momentDuration in render to the actual method
|
const momentDuration = this.momentDuration;
|
||||||
|
const ISO_8601parse = this.ISO_8601parse;
|
||||||
if (error) {
|
if (error) {
|
||||||
|
let htmlRegEx = /<\/?\w+((\s+\w+(\s*=\s*(?:".*?"|'.*?'|[\^'">\s]+))?)+\s*|\s*)\/?>/gm;
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<span className="text-white">
|
||||||
Error: {error.message} -- Cannot get {error.config.url}
|
<span>{}</span>
|
||||||
</React.Fragment>
|
Error: {error.message} -- {error.response.data && error.response.data.error.message.replace(htmlRegEx, '')}
|
||||||
|
</span>
|
||||||
);
|
);
|
||||||
} else if (!isLoaded) {
|
} else if (!isLoaded) {
|
||||||
return <React.Fragment>Loading...</React.Fragment>;
|
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>
|
||||||
<Col >
|
<span className="h5 text-white">{VideoDetails.snippet.title}</span>
|
||||||
{/* codice per tabs reccomenders */}
|
<Tabs defaultActiveKey="video" id="tabs">
|
||||||
<Tabs defaultActiveKey={1} id="tabs" animation={0}>
|
<Tab className="text-white" eventKey="video" title="Video">
|
||||||
<Tab eventKey={1} title="Video">
|
<p>
|
||||||
<div style={{color : 'white'}}>
|
<b>ID Video: </b>{VideoDetails.id}<br />
|
||||||
{this.state.VideoDetails.map(function(item,index){
|
<b>Published: </b>{ISO_8601parse(VideoDetails.snippet.publishedAt)}<br />
|
||||||
return(
|
<b>Channel name: </b>{VideoDetails.snippet.channelTitle}<br />
|
||||||
<div key={index}>
|
<b>Description: </b><Linkify>{VideoDetails.snippet.description}</Linkify><br />
|
||||||
<h5>{item.snippet.title}</h5>
|
<b>Tags: </b>{VideoDetails.snippet.tags ?
|
||||||
<p><b>ID Video :</b> {item.id}<br/>
|
VideoDetails.snippet.tags.map((tag, i) =>
|
||||||
<b>Publish Time :</b> {item.snippet.publishedAt.replace(/(\d+)-(\d+)-(\d+)T(\d+):(\d+):(\d+).000Z/,function(match,p1,p2,p3,p4,p5,p6){
|
(<span key={i}><Link to={{ pathname: '/search/' + tag }}>{tag}</Link>{" "}</span>))
|
||||||
return(p3+'/'+p2+'/'+p1+' - '+p4+':'+p5+':'+p6);
|
: ""}
|
||||||
})}<br/>
|
|
||||||
<b>Channel Name :</b> {item.snippet.channelTitle}<br/>
|
|
||||||
<b>Description :</b><br/><Linkify>{item.snippet.description}</Linkify><br/>
|
|
||||||
<b>Tags :</b><br/>{item.snippet.tags.map(function(element,index){
|
|
||||||
if(index===4)
|
|
||||||
return (<br/>);
|
|
||||||
return(
|
|
||||||
<span key={index} style={{margin : '0.5rem',textDecoration : 'underline'}}>{element}</span>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab eventKey={2} title="Tecnical Informations">
|
<Tab className="text-white" eventKey="techinfo" title="Tecnical Informations">
|
||||||
<div style={{color:'white'}}>
|
<p>
|
||||||
{this.state.VideoDetails.map(function (item,index) {
|
<b>Duration: </b>{momentDuration(VideoDetails.contentDetails.duration)}<br />
|
||||||
return(
|
<b>Definition: </b> {VideoDetails.contentDetails.definition}<br />
|
||||||
<div key={index}>
|
<b>Dimension: </b> {VideoDetails.contentDetails.dimension}<br />
|
||||||
<h5 style={{marginTop : '1rem'}}>{item.snippet.title}</h5>
|
<b>Views: </b> {VideoDetails.statistics.viewCount}<br />
|
||||||
<p><b>Duration :</b>{ momentDuration(item.contentDetails.duration) }<br/>
|
<b>Likes: </b> {VideoDetails.statistics.likeCount}{String.fromCodePoint(0x1F44D)}<br />
|
||||||
<b>Definition :</b> {item.contentDetails.definition}<br/>
|
<b>Dislikes: </b> {VideoDetails.statistics.dislikeCount}{String.fromCodePoint(0x1F44E)}
|
||||||
<b>Dimension :</b> {item.contentDetails.dimension}<br/>
|
|
||||||
<b> Views :</b> {item.statistics.viewCount}<br/>
|
|
||||||
<b>Likes :</b> {item.statistics.likeCount}<br/>
|
|
||||||
<b>Dislikes :</b> {item.statistics.dislikeCount}
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab eventKey={3} title="Comment">
|
<Tab eventKey="comments" title="Comment">
|
||||||
<div>
|
{comments.map(function (comment, index) {
|
||||||
{this.state.comments.map(function (item,index) {
|
return (
|
||||||
return(
|
<Card key={index} className="my-1">
|
||||||
<div key={index}>
|
|
||||||
<Card style={{width: '30rem',fontSize : 'small',borderRadius : '1rem'}} className="my-1">
|
|
||||||
<Card.Body>
|
<Card.Body>
|
||||||
<Card.Title>
|
<Card.Title>
|
||||||
<Card.Img src={item.snippet.topLevelComment.snippet.authorProfileImageUrl} style={{width : '3rem', height : '3rem'}} />{item.snippet.topLevelComment.snippet.authorDisplayName}
|
<Card.Img src={comment.snippet.topLevelComment.snippet.authorProfileImageUrl} style={{ width: '3rem', height: '3rem' }} />
|
||||||
|
{comment.snippet.topLevelComment.snippet.authorDisplayName}
|
||||||
</Card.Title>
|
</Card.Title>
|
||||||
<Card.Text>
|
<Card.Text>
|
||||||
<Linkify>
|
<Linkify>
|
||||||
{item.snippet.topLevelComment.snippet.textDisplay}
|
{comment.snippet.topLevelComment.snippet.textOriginal}
|
||||||
</Linkify>
|
</Linkify>
|
||||||
</Card.Text>
|
</Card.Text>
|
||||||
</Card.Body>
|
</Card.Body>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</div>
|
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab eventKey={4} title="Wikipedia">
|
<Tab className="text-white" eventKey="wikipedia" title="Wikipedia">
|
||||||
<div>
|
<Wikipedia
|
||||||
|
title={'undefined' !== typeof this.props.location.state ? this.props.location.state.title : undefined}
|
||||||
</div>
|
title2={ytclear(this.state.VideoDetails.snippet.title).split('-')[1]}
|
||||||
|
artist={'undefined' !== typeof this.props.location.state ? this.props.location.state.artist : undefined}
|
||||||
|
artist2={ytclear(this.state.VideoDetails.snippet.title).split('-')[0]}
|
||||||
|
key={this.props.videoId}
|
||||||
|
videoId={this.props.videoId}
|
||||||
|
/>
|
||||||
</Tab>
|
</Tab>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</Col>
|
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoInfo.propTypes = {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
export default VideoInfo;
|
export default VideoInfo;
|
||||||
+60
-35
@@ -1,27 +1,29 @@
|
|||||||
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
|
||||||
import './css/VideoList.css';
|
|
||||||
/*eslint no-console: ["error", { allow: ["warn", "error", "info"] }] */
|
/*eslint no-console: ["error", { allow: ["warn", "error", "info"] }] */
|
||||||
|
|
||||||
class VideoList extends React.Component {
|
class VideoList extends React.Component {
|
||||||
constructor(props) {
|
state = {
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
error: null,
|
error: null,
|
||||||
isLoaded: false,
|
isLoaded: false,
|
||||||
items: [],
|
items: [],
|
||||||
headers: null
|
headers: null
|
||||||
};
|
};
|
||||||
this.getThumbnails = this.getThumbnails.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
localStorage['fixedVideoList'] ?
|
||||||
|
this.setState({
|
||||||
|
items: this.shuffleArray(JSON.parse(localStorage.getItem('fixedVideoList'))),
|
||||||
|
isLoaded: true
|
||||||
|
}) :
|
||||||
axios.get('http://site1825.tw.cs.unibo.it/video.json').then(
|
axios.get('http://site1825.tw.cs.unibo.it/video.json').then(
|
||||||
response => {
|
response => {
|
||||||
this.shuffleArray(response.data);
|
this.shuffleArray(response.data);
|
||||||
this.getThumbnails(response.data);
|
this.getThumbnails(response.data)
|
||||||
|
.then(videoList => localStorage.setItem('fixedVideoList', JSON.stringify(videoList)));
|
||||||
},
|
},
|
||||||
// Note: it's important to handle errors here
|
// Note: it's important to handle errors here
|
||||||
// instead of a catch() block so that we don't swallow
|
// instead of a catch() block so that we don't swallow
|
||||||
@@ -33,21 +35,21 @@ class VideoList extends React.Component {
|
|||||||
error
|
error
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// METODI
|
// METODI
|
||||||
getThumbnails(videoItems) {
|
getThumbnails(videoItems) {
|
||||||
let idToLookFor = videoItems.map(item => item.videoID);
|
let idToLookFor = videoItems.map(item => item.videoID);
|
||||||
let finalChunk = (videoItems.length % 50) + 100;
|
let finalChunk = (videoItems.length % 50) + 100;
|
||||||
axios
|
return axios
|
||||||
.all([
|
.all([
|
||||||
// chain 3 parallel get
|
// chain 3 parallel get
|
||||||
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.slice(0, 50).toString(),
|
id: idToLookFor.slice(0, 50).toString(),
|
||||||
key: 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig',
|
key: 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig', // 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig' in production
|
||||||
fields: 'items(id,snippet/thumbnails/medium)'
|
fields: 'items(id,snippet/thumbnails/medium)'
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
@@ -56,7 +58,7 @@ class VideoList extends React.Component {
|
|||||||
params: {
|
params: {
|
||||||
part: 'snippet',
|
part: 'snippet',
|
||||||
id: idToLookFor.slice(50, 100).toString(),
|
id: idToLookFor.slice(50, 100).toString(),
|
||||||
key: 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig',
|
key: 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig', // 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig' in production
|
||||||
fields: 'items(id,snippet/thumbnails/medium)'
|
fields: 'items(id,snippet/thumbnails/medium)'
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
@@ -65,46 +67,47 @@ class VideoList extends React.Component {
|
|||||||
params: {
|
params: {
|
||||||
part: 'snippet',
|
part: 'snippet',
|
||||||
id: idToLookFor.slice(100, finalChunk).toString(),
|
id: idToLookFor.slice(100, finalChunk).toString(),
|
||||||
key: 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig',
|
key: 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig', // 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig' in production
|
||||||
fields: 'items(id,snippet/thumbnails/medium)'
|
fields: 'items(id,snippet/thumbnails/medium)'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
])
|
])
|
||||||
.then(
|
.then(
|
||||||
axios.spread((res1, res2, res3) => {
|
axios.spread((res1, res2, res3) => {
|
||||||
let allres = [].concat(
|
[...res1.data.items, ...res2.data.items, ...res3.data.items]
|
||||||
res1.data.items,
|
.map(resCurrentValue =>
|
||||||
res2.data.items,
|
|
||||||
res3.data.items
|
|
||||||
);
|
|
||||||
allres.map(resCurrentValue => {
|
|
||||||
Object.defineProperty(
|
Object.defineProperty(
|
||||||
videoItems.find(videoItem => {
|
videoItems.find(videoItem => {
|
||||||
return videoItem.videoID === resCurrentValue.id;
|
return videoItem.videoID === resCurrentValue.id;
|
||||||
}),
|
}),
|
||||||
'thumbnail',
|
'thumbnail',
|
||||||
{ value: resCurrentValue.snippet.thumbnails.medium.url }
|
{
|
||||||
|
value: resCurrentValue.snippet.thumbnails.medium.url,
|
||||||
|
enumerable: true
|
||||||
|
}
|
||||||
|
)
|
||||||
);
|
);
|
||||||
});
|
|
||||||
this.setState({
|
this.setState({
|
||||||
isLoaded: true,
|
isLoaded: true,
|
||||||
items: videoItems
|
items: videoItems
|
||||||
});
|
});
|
||||||
|
return new Promise((resolve, reject) => resolve(videoItems))
|
||||||
})
|
})
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
shuffleArray(videoarray) {
|
shuffleArray(videoArray) {
|
||||||
for (let i = videoarray.length - 1; i > 0; i--) {
|
for (let i = videoArray.length - 1; i > 0; i--) {
|
||||||
const j = Math.floor(Math.random() * (i + 1));
|
const j = Math.floor(Math.random() * (i + 1));
|
||||||
[videoarray[i], videoarray[j]] = [videoarray[j], videoarray[i]]; // eslint-disable-line no-param-reassign
|
[videoArray[i], videoArray[j]] = [videoArray[j], videoArray[i]]; // eslint-disable-line no-param-reassign
|
||||||
}
|
}
|
||||||
|
return videoArray
|
||||||
// Durstenfeld shuffle.
|
// Durstenfeld shuffle.
|
||||||
// https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm
|
// https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm
|
||||||
}
|
}
|
||||||
|
|
||||||
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>
|
||||||
@@ -112,21 +115,16 @@ 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>
|
||||||
{items.map(item => (
|
{items.map(item => (
|
||||||
<Col key={item.videoID} lg={{ span: 3 }} md="6">
|
<Col key={item.videoID} lg={{ span: 3 }} md="6">
|
||||||
<Card className="my-1 carta">
|
<Card className="my-1 carta">
|
||||||
<Link
|
<Link to={{
|
||||||
to={{
|
|
||||||
pathname: '/video/' + item.videoID,
|
pathname: '/video/' + item.videoID,
|
||||||
state: {
|
state: {
|
||||||
artist: item.artist,
|
artist: item.artist,
|
||||||
@@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+75
-49
@@ -1,59 +1,35 @@
|
|||||||
import React, { Component } from 'react'; // eslint-disable-line no-unused-vars
|
import React from 'react'; // eslint-disable-line no-unused-vars
|
||||||
import YouTube from 'react-youtube'; // eslint-disable-line no-unused-vars
|
import YouTube from 'react-youtube'; // eslint-disable-line no-unused-vars
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import { withRouter } from 'react-router-dom';
|
||||||
/* eslint no-console: ["error", { allow: ["info", "error", "warn"] }] */
|
/* eslint no-console: ["error", { allow: ["info", "error", "warn"] }] */
|
||||||
|
|
||||||
class VideoPlayer extends Component {
|
class VideoPlayer extends React.Component {
|
||||||
constructor(props) {
|
state = {
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
opt: {
|
opt: {
|
||||||
height: '390',
|
// height: '390',
|
||||||
width: '640',
|
// width: '640',
|
||||||
playerVars: {
|
playerVars: {
|
||||||
// https://developers.google.com/youtube/player_parameters
|
// https://developers.google.com/youtube/player_parameters
|
||||||
autoplay: 0,
|
autoplay: 0,
|
||||||
modestbranding: 1
|
modestbranding: 1,
|
||||||
|
fs: 0,
|
||||||
|
iv_load_policy: 3,
|
||||||
|
rel: 0,
|
||||||
|
origin//: 'http://site1854.tw.cs.unibo.it'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
videoId: '0J2QdDbelmY',
|
|
||||||
promise1: null,
|
promise1: null,
|
||||||
promise2: null,
|
promise2: Promise,
|
||||||
outsideReject1: null,
|
outsideReject1: null,
|
||||||
outsideReject2: null
|
outsideReject2: null
|
||||||
};
|
};
|
||||||
this._onPlay = this._onPlay.bind(this);
|
|
||||||
this._onStateChange = this._onStateChange.bind(this);
|
|
||||||
this._onReady = this._onReady.bind(this);
|
|
||||||
}
|
|
||||||
componentWillUpdate(nextProps, nextState) {
|
|
||||||
if (nextProps.match.params.id === this.props.match.params.id) {
|
|
||||||
} else if (nextProps.match.params.id) {
|
|
||||||
this.setState((state, props) => {
|
|
||||||
return { videoId: props.match.params.id };
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
|
||||||
// if (nextProps.location !== this.props.location) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillMount() {
|
|
||||||
if (this.props.match.params.id)
|
|
||||||
this.setState((state, props) => {
|
|
||||||
return { videoId: props.match.params.id };
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
|
||||||
<YouTube
|
<YouTube
|
||||||
opts={this.state.opt}
|
opts={this.state.opt}
|
||||||
videoId={this.state.videoId}
|
videoId={this.props.videoId}
|
||||||
onReady={this._onReady}
|
onReady={this._onReady}
|
||||||
onPlay={this._onPlay}
|
onPlay={this._onPlay}
|
||||||
onError={this._onError}
|
onError={this._onError}
|
||||||
@@ -61,18 +37,17 @@ class VideoPlayer extends Component {
|
|||||||
className="embed-responsive-item"
|
className="embed-responsive-item"
|
||||||
containerClassName="embed-responsive embed-responsive-16by9"
|
containerClassName="embed-responsive embed-responsive-16by9"
|
||||||
/>
|
/>
|
||||||
</React.Fragment>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// access to player in all event handlers via event.target
|
// access to player in all event handlers via event.target
|
||||||
_onError(event) {
|
_onError(event) {
|
||||||
console.error('Error: ', event);
|
console.error('Player error: ', event);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onPlay(event) {}
|
_onPlay(event) { }
|
||||||
|
|
||||||
_onReady(event) {}
|
_onReady(event) { }
|
||||||
|
|
||||||
_onStateChange(event) {
|
_onStateChange(event) {
|
||||||
let timerId1, timerId2;
|
let timerId1, timerId2;
|
||||||
@@ -102,8 +77,8 @@ class VideoPlayer extends Component {
|
|||||||
promise1: new Promise((resolve, reject) => {
|
promise1: new Promise((resolve, reject) => {
|
||||||
timerId1 = window.setInterval(() => {
|
timerId1 = window.setInterval(() => {
|
||||||
if (event.target.getCurrentTime() > 15)
|
if (event.target.getCurrentTime() > 15)
|
||||||
resolve(event.target.j.videoData.video_id);
|
resolve(event.target.getVideoData().video_id);
|
||||||
}, 1000);
|
}, 500);
|
||||||
this.setState({ outsideReject1: reject });
|
this.setState({ outsideReject1: reject });
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
@@ -111,31 +86,82 @@ class VideoPlayer extends 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://localhost:8000/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 => console.info(error)
|
error => this.setState({ error })//console.error(error, videoIdWatched.toString())
|
||||||
);
|
);
|
||||||
// local storage logic for recent reccomender
|
// 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') {
|
||||||
|
//per primo video
|
||||||
|
tmp.push({
|
||||||
|
'id': videoIdWatched.toString(),
|
||||||
|
'lastWatched': new Date(),
|
||||||
|
'timesWatched': 1,
|
||||||
|
'prevVideos': []
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//Prima volta video generico
|
||||||
|
tmp.push({
|
||||||
|
'id': videoIdWatched.toString(),
|
||||||
|
'lastWatched': new Date(),
|
||||||
|
'timesWatched': 1,
|
||||||
|
'prevVideos': [{ id: [localStorage["prevId"]].toString() }]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//altre volte
|
||||||
|
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()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp.sort((a, b) => new Date(b.lastWatched).getTime() - new Date(a.lastWatched).getTime());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
localStorage.setItem('lastWatched', JSON.stringify(tmp));
|
||||||
|
//.finally(()=>{})
|
||||||
clearInterval(timerId1);
|
clearInterval(timerId1);
|
||||||
|
return new Promise ((resolve,reject) => resolve(videoIdWatched))
|
||||||
},
|
},
|
||||||
error => console.error(error)
|
error => console.error(error)
|
||||||
)
|
)
|
||||||
.finally(() => this.setState({ promise1: null }));
|
.finally((id) => 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((res) => { this.setState({ promise2: null, outsideReject2: null }) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_onStateChange = this._onStateChange.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default VideoPlayer;
|
export default withRouter(VideoPlayer);
|
||||||
|
|||||||
@@ -0,0 +1,324 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import wikijs from 'wikijs';
|
||||||
|
import wdk from 'wikidata-sdk';
|
||||||
|
import axios from 'axios';
|
||||||
|
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 {
|
||||||
|
|
||||||
|
state = {
|
||||||
|
wikidata: null,
|
||||||
|
wikipedia: null,
|
||||||
|
musicbrainz: null,
|
||||||
|
props: {},
|
||||||
|
error: null,
|
||||||
|
isWikiLoaded: false,
|
||||||
|
isWDataLoaded: false,
|
||||||
|
isMBLoaded: false,
|
||||||
|
isLoaded: false,
|
||||||
|
wikidatakeys: null,
|
||||||
|
wikipediakeys: null
|
||||||
|
};
|
||||||
|
|
||||||
|
ISO_8601toYYYY(a) {
|
||||||
|
return moment(a, [moment.ISO_8601, 'YYYY']).format('YYYY');
|
||||||
|
}
|
||||||
|
|
||||||
|
getExternalLink(P, value) {
|
||||||
|
switch (P) {
|
||||||
|
case "P436": //MB release group id
|
||||||
|
return (<a target="_blank" rel="noopener noreferrer" href={`https://musicbrainz.org/release-group/${value}`}>{`${value}`}</a>)
|
||||||
|
case "P435": // MB work id
|
||||||
|
return (<a target="_blank" rel="noopener noreferrer" href={`https://musicbrainz.org/work/${value}`}>{`${value}`}</a>)
|
||||||
|
case "P1954": // discogs id
|
||||||
|
return (<a target="_blank" rel="noopener noreferrer" href={`https://www.discogs.com/master/${value}`}>{`${value}`}</a>)
|
||||||
|
case "P2624": // metrolyrics id
|
||||||
|
return (<a target="_blank" rel="noopener noreferrer" href={`http://www.metrolyrics.com/${value}`}>{`${value}`}</a>)
|
||||||
|
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>)
|
||||||
|
case "P1827":
|
||||||
|
return (<a target="_blank" rel="noopener noreferrer" href={`https://musicbrainz.org/iswc/${value}`}>{value}</a>)
|
||||||
|
default:
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getWikidataPage(wikidataPXXXXResID) {
|
||||||
|
return axios.get(wdk.getEntities(wikidataPXXXXResID, 'en'))
|
||||||
|
.then(wikidataPage => {
|
||||||
|
let wikidatatmp = wikidataPage.data.entities[Object.keys(wikidataPage.data.entities)[0]];
|
||||||
|
this.setState({
|
||||||
|
wikidata: wikidatatmp
|
||||||
|
});
|
||||||
|
axios.all([
|
||||||
|
axios.get(wdk.getManyEntities(Object.keys(wikidatatmp.claims), 'en'))
|
||||||
|
, axios.get(wdk.getManyEntities(
|
||||||
|
Object.keys(wikidatatmp.claims)
|
||||||
|
.map(x => wikidatatmp.claims[x][0].mainsnak.datavalue.value.id)
|
||||||
|
.filter(x => typeof x === 'string'), 'en'))
|
||||||
|
])
|
||||||
|
.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()]))
|
||||||
|
.then(wikipediaRes => this.setState({
|
||||||
|
wikipedia: {
|
||||||
|
// "desc": wikipediaRes[1],
|
||||||
|
"info": wikipediaRes[0].general
|
||||||
|
},
|
||||||
|
wikipediakeys: Object.keys(wikipediaRes[0].general),
|
||||||
|
isWikiLoaded: true
|
||||||
|
}))
|
||||||
|
else {
|
||||||
|
this.findWikiPage();
|
||||||
|
}
|
||||||
|
}, error => console.error(error))
|
||||||
|
}
|
||||||
|
|
||||||
|
findWikiPage = () => {
|
||||||
|
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 => {
|
||||||
|
return Promise.all([res.fullInfo()]);
|
||||||
|
}) // find by props.title (props.artist song)
|
||||||
|
.then(wikipediaRes => this.setState({
|
||||||
|
wikipedia: {
|
||||||
|
"info": wikipediaRes[0].general
|
||||||
|
},
|
||||||
|
wikipediakeys: Object.keys(wikipediaRes[0].general),
|
||||||
|
isWikiLoaded: true
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
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
|
||||||
|
this.getWikidataPage(wdk.simplify.sparqlResults(wikidataP1651Res.data))// set in state wikidata
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
catch(e){
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
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()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
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 }));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// shouldComponentUpdate(nextProps, nextState) {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// componentDidUpdate(prevProps, prevState) {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// componentWillUnmount() {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { wikidata, wikipedia, musicbrainz, error, isWikiLoaded, isWDataLoaded, isMBLoaded } = this.state;
|
||||||
|
const ISO_8601toYYYY = this.ISO_8601toYYYY;
|
||||||
|
if (error) {
|
||||||
|
return <React.Fragment>Error: {error.message}</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 {
|
||||||
|
return (
|
||||||
|
<Table size="sm">
|
||||||
|
<tbody>
|
||||||
|
{isWikiLoaded &&
|
||||||
|
this.state.wikipediakeys.map(key => (
|
||||||
|
<tr key={key}>
|
||||||
|
<td>{key}</td>
|
||||||
|
<td>{wikipedia.info[key].toLocaleString()}</td>
|
||||||
|
</tr>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
{isWDataLoaded &&
|
||||||
|
this.state.wikidatakeys.map(key => (
|
||||||
|
<tr key={key[0]}>
|
||||||
|
<td>{`${key[0]} -
|
||||||
|
${key[1].labels.en ? key[1].labels.en.value : ""} `}
|
||||||
|
</td>
|
||||||
|
<td>{
|
||||||
|
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" ? // 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 :
|
||||||
|
"??"}`}
|
||||||
|
</a> {`(${wikidata.claims[key[0]][0].mainsnak.datavalue.value.id})`}</> :
|
||||||
|
typeof wikidata.claims[key[0]][0].mainsnak.datavalue.value.time === "string" ?
|
||||||
|
ISO_8601toYYYY(wikidata.claims[key[0]][0].mainsnak.datavalue.value.time.toString()) :
|
||||||
|
""
|
||||||
|
}</td>
|
||||||
|
</tr>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
{isMBLoaded &&
|
||||||
|
musicbrainz.relations.map((relation, i) => {
|
||||||
|
if (relation["target-type"] === "artist")
|
||||||
|
return (<tr key={i}>
|
||||||
|
<td>{relation.type}</td>
|
||||||
|
<td>{relation.artist.name}</td>
|
||||||
|
</tr>);
|
||||||
|
else if (relation["target-type"] === "url")
|
||||||
|
return (<tr key={i}>
|
||||||
|
<td>{relation.type}</td>
|
||||||
|
<td><a target="_blank" rel="noopener noreferrer" href={relation.url.resource}>{relation.type}</a></td>
|
||||||
|
</tr>)
|
||||||
|
else
|
||||||
|
return ("");
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</Table>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Wikipedia;
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
import React, { Component } from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { Row, Col, Button, Collapse } from 'react-bootstrap';
|
|
||||||
// import Random from './reccomenders/Random';
|
|
||||||
// import Related from './reccomenders/Related';
|
|
||||||
// and so on..
|
|
||||||
|
|
||||||
class Suggestion extends Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillMount() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps, nextState) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUpdate(nextProps, nextState) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps, prevState) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
let a =['','','','','','','','','','',''];
|
|
||||||
return (
|
|
||||||
<React.Fragment>
|
|
||||||
<Col xs="10">
|
|
||||||
<Row>
|
|
||||||
{a.map((x,i) => <Col xs={{'span': 10, 'offset': 1}} className="mt-1 border border-danger">- video {i}</Col>)}
|
|
||||||
</Row>
|
|
||||||
</Col>
|
|
||||||
<Col className="mt-1 mr-2 border border-danger">
|
|
||||||
{a.map((x,i) => i)}
|
|
||||||
?? box utile o superfluo?
|
|
||||||
</Col>
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Suggestion.propTypes = {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Suggestion;
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
import React, { Component } from 'react';
|
|
||||||
// import PropTypes from 'prop-types';
|
|
||||||
import wikijs from 'wikijs';
|
|
||||||
|
|
||||||
class Wikipedia extends Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
data: {},
|
|
||||||
infobox: {},
|
|
||||||
error: null,
|
|
||||||
isLoaded: false
|
|
||||||
};
|
|
||||||
this.getWikiBox = this.getWikiBox.bind(this);
|
|
||||||
this.raffina = this.raffina.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
getWikiBox(name){
|
|
||||||
wikijs()
|
|
||||||
.page(name)
|
|
||||||
.then(page => page.fullInfo())
|
|
||||||
.then(infobox => console.log('infobox', infobox)
|
|
||||||
//this.setState({ infobox })
|
|
||||||
);
|
|
||||||
//console.log('infobox', this.state.infobox)
|
|
||||||
}
|
|
||||||
|
|
||||||
raffina(results){
|
|
||||||
console.log('raffina',results);
|
|
||||||
return results[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
// componentWillMount() {
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
componentWillMount() {
|
|
||||||
wikijs().find(this.props.query, this.raffina).then(data => {
|
|
||||||
this.setState({
|
|
||||||
data,
|
|
||||||
isLoaded: true
|
|
||||||
});
|
|
||||||
console.log(data.html());
|
|
||||||
//this.getWikiBox(data.results[0]);
|
|
||||||
}, error => {
|
|
||||||
console.error(error);
|
|
||||||
this.setState({
|
|
||||||
isLoaded: true,
|
|
||||||
error
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// componentWillReceiveProps(nextProps) {
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
// shouldComponentUpdate(nextProps, nextState) {
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
// componentWillUpdate(nextProps, nextState) {
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
// componentDidUpdate(prevProps, prevState) {
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
// componentWillUnmount() {
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { data, error, isLoaded } = this.state;
|
|
||||||
if (error) {
|
|
||||||
return (
|
|
||||||
<React.Fragment>
|
|
||||||
Error: {error.message} -- Cannot get {error.config.url}
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
} else if (!isLoaded) {
|
|
||||||
return <React.Fragment>Loading...</React.Fragment>;
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{/* <p>risultato ricerca wikipedia: { data.results[0] }</p> */}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Wikipedia;
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
.person-wrapper {
|
||||||
|
margin-bottom: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-pic {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background-image: none;
|
||||||
|
border: none;
|
||||||
|
border-radius: 0;
|
||||||
|
background-color: #2892D7;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
+73
-8
@@ -1,16 +1,81 @@
|
|||||||
.upperSection{
|
.upperSection{
|
||||||
background-color:#000000;
|
display: fixed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* .sticky{
|
.blackBg{
|
||||||
position: -webkit-sticky;
|
background-color:#000000;
|
||||||
position: sticky;
|
}
|
||||||
top: 0;
|
|
||||||
z-index: 1040;
|
|
||||||
} */
|
|
||||||
|
|
||||||
.downSection{
|
.downSection{
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
/* margin-top: 1vh; */
|
}
|
||||||
|
|
||||||
|
.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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+6
-1
@@ -6,13 +6,18 @@
|
|||||||
|
|
||||||
.navbar-light .navbar-nav .nav-link:hover, .navbar-light .navbar-nav .nav-link:focus {
|
.navbar-light .navbar-nav .nav-link:hover, .navbar-light .navbar-nav .nav-link:focus {
|
||||||
color: rgba(255,255,255);
|
color: rgba(255,255,255);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-light .navbar-nav .nav-link:hover, .navbar-light {
|
.navbar-light .navbar-nav .nav-link:hover, .navbar-light {
|
||||||
color: rgba(248, 245, 245, 0.808);
|
color: rgba(248, 245, 245, 0.808);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.navbar-light .navbar-nav .show > .nav-link, .navbar-light .navbar-nav .active > .nav-link, .navbar-light .navbar-nav .nav-link.show, .navbar-light .navbar-nav .nav-link.active {
|
.navbar-light .navbar-nav .show > .nav-link, .navbar-light .navbar-nav .active > .nav-link, .navbar-light .navbar-nav .nav-link.show, .navbar-light .navbar-nav .nav-link.active {
|
||||||
color: rgb(248, 245, 245, 0,808);
|
color: rgb(248, 245, 245, 0,808);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// Required
|
||||||
|
@import "~bootstrap/scss/functions";
|
||||||
|
@import "~bootstrap/scss/variables";
|
||||||
|
@import "~bootstrap/scss/mixins";
|
||||||
|
// To extend
|
||||||
|
@import '~bootstrap/scss/utilities/text';
|
||||||
|
|
||||||
|
a[aria-selected=false]{
|
||||||
|
@extend .text-white;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
a[target=_blank]{
|
||||||
|
background: transparent url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAAXklEQVQoka2QwQ3AMAwCs1N28k7eiZ3oI7IcU6efBomXOREyxhUZ2brTdNAcVB2BaJgCVcDAalJLXsB+iLAjm1pAwzHWHD3gWMcMg/ERMjKfFOHVqMEGqEM/gKP/6gE2f+h+Z5P45wAAAABJRU5ErkJggg==') center right no-repeat;
|
||||||
|
padding-right: 14px;
|
||||||
|
|
||||||
|
}
|
||||||
|
tbody a{
|
||||||
|
color: #DF691A !important;
|
||||||
|
}
|
||||||
+12
File diff suppressed because one or more lines are too long
+12
File diff suppressed because one or more lines are too long
+12
File diff suppressed because one or more lines are too long
+12
File diff suppressed because one or more lines are too long
+12
File diff suppressed because one or more lines are too long
+12
File diff suppressed because one or more lines are too long
+12
File diff suppressed because one or more lines are too long
+12
File diff suppressed because one or more lines are too long
+12
File diff suppressed because one or more lines are too long
+12
File diff suppressed because one or more lines are too long
+12
File diff suppressed because one or more lines are too long
+12
File diff suppressed because one or more lines are too long
+12
File diff suppressed because one or more lines are too long
+12
File diff suppressed because one or more lines are too long
+12
File diff suppressed because one or more lines are too long
+12
File diff suppressed because one or more lines are too long
+12
File diff suppressed because one or more lines are too long
+12
File diff suppressed because one or more lines are too long
+12
File diff suppressed because one or more lines are too long
+12
File diff suppressed because one or more lines are too long
+12
File diff suppressed because one or more lines are too long
+16
-2
@@ -1,10 +1,24 @@
|
|||||||
|
// 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';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
import registerServiceWorker from './registerServiceWorker';
|
import registerServiceWorker from './registerServiceWorker';
|
||||||
import { HashRouter, BrowserRouter } from 'react-router-dom';
|
import { HashRouter, BrowserRouter } from 'react-router-dom'; // eslint-disable-line
|
||||||
|
|
||||||
ReactDOM.render(<HashRouter><App /></HashRouter>, document.getElementById('root'));
|
localStorage['lastWatched'] ? function () { }() : localStorage.setItem('lastWatched', JSON.stringify([]))
|
||||||
|
localStorage['first'] ? function () { }() : localStorage.setItem('first', JSON.stringify([]))
|
||||||
|
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();
|
registerServiceWorker();
|
||||||
+56
-29
@@ -1,37 +1,38 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import 'bootstrap/dist/css/bootstrap.css';
|
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import createpageToken from 'youtube-page-token';
|
import createpageToken from 'youtube-page-token';
|
||||||
import {Card} 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";
|
||||||
|
|
||||||
class RecommenderRandom extends Component{
|
class RecommenderRandom extends Component {
|
||||||
constructor(props){
|
state = {
|
||||||
super(props);
|
items: [],
|
||||||
this.state={
|
|
||||||
items : [],
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount(){
|
ISO_8601parse(a) {
|
||||||
|
return moment(a, moment.ISO_8601).format('ddd, DD/MM/YYYY hh:mm:ss');
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
let pos = Math.floor(Math.random() * 500);
|
let pos = Math.floor(Math.random() * 500);
|
||||||
let pageToken = createpageToken(pos); /* createPageToken(pos) restituisce il pageToken relativo al numero
|
let pageToken = createpageToken(pos); /* createPageToken(pos) restituisce il pageToken relativo al numero
|
||||||
di pagina che gli viene passato(in questo caso pos) che verrai poi usato
|
di pagina che gli viene passato(in questo caso pos) che verrai poi usato
|
||||||
come paramentro da axios per ottenere una determinata pagina di risultati */
|
come parametro da axios per ottenere una determinata pagina di risultati */
|
||||||
|
|
||||||
axios.get("https://www.googleapis.com/youtube/v3/search", {
|
axios.get("https://www.googleapis.com/youtube/v3/search", {
|
||||||
params: {
|
params: {
|
||||||
'part': 'snippet',
|
'part': 'snippet',
|
||||||
'topicId' : '/m/04rlf', //Filtro per la musica.In questo caso il valore è quello della parent directory
|
'topicId': '/m/04rlf', //Filtro per la musica.In questo caso il valore è quello della parent directory
|
||||||
'type' : 'video', //che contiene tutti i generi di musica
|
'type': 'video', //che contiene tutti i generi di musica
|
||||||
'maxResults': '21',
|
'maxResults': '21',
|
||||||
'pageToken' : pageToken,
|
'pageToken': pageToken,
|
||||||
'key': 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig'
|
'key': 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig'
|
||||||
}
|
}
|
||||||
}).then(
|
}).then(
|
||||||
response => {
|
response => {
|
||||||
this.setState({
|
this.setState({
|
||||||
items : response.data.items,
|
items: response.data.items,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
@@ -40,38 +41,64 @@ class RecommenderRandom extends Component{
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
render(){
|
render() {
|
||||||
|
const ISO_8601parse = this.ISO_8601parse;
|
||||||
|
if (window.innerWidth < 992) {
|
||||||
|
return (<React.Fragment>
|
||||||
|
{this.state.items.map(function (item, index) {
|
||||||
return (
|
return (
|
||||||
<div style={{width: '100rem',height:'100rem'}}>
|
<Col key={index} md='4'>
|
||||||
{this.state.items.map(function (item,index) {
|
|
||||||
return(
|
|
||||||
<div key={index} style={{margin: '1rem',float: 'left'}}>
|
|
||||||
<Card>
|
<Card>
|
||||||
<Link
|
<Link
|
||||||
to={{
|
to={{
|
||||||
pathname: '/video/' + item.id.videoId,
|
pathname: '/video/' + item.id.videoId,
|
||||||
|
search: "?ref=Random"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Card.Img
|
<Card.Img
|
||||||
src={item.snippet.thumbnails.high.url}
|
src={item.snippet.thumbnails.high.url}
|
||||||
alt={'Thumbnail of ' + item.title}
|
alt={'Thumbnail of ' + item.snippet.title}
|
||||||
style={{width:'30rem',height:'20rem'}}
|
|
||||||
/>
|
/>
|
||||||
<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} - {item.snippet.publishedAt.replace(/(\d+)-(\d+)-(\d+)T(\d+):(\d+):(\d+).000Z/,function(match,p1,p2,p3,p4,p5,p6){
|
{item.snippet.channelTitle} - {ISO_8601parse(item.snippet.publishedAt)}<br />
|
||||||
return(p3+'/'+p2+'/'+p1+' at '+p4+':'+p5+':'+p6); //Funzione che trasforma la data e ora di pubblicazione dal formato ISO nel normale formato da cristiani
|
<span>Reccomender: Random</span>
|
||||||
})}
|
|
||||||
</Card.Title>
|
</Card.Title>
|
||||||
</Card.ImgOverlay>
|
</Card.ImgOverlay>
|
||||||
</Link>
|
</Link>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</Col>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</div>
|
</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;
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
import React from 'react';
|
||||||
|
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"] }] */
|
||||||
|
import moment from "moment";
|
||||||
|
|
||||||
|
class Recent extends React.Component {
|
||||||
|
state = {
|
||||||
|
error: null,
|
||||||
|
isLoaded: false,
|
||||||
|
items: [],
|
||||||
|
headers: null
|
||||||
|
};
|
||||||
|
|
||||||
|
ISO_8601parse(a) {
|
||||||
|
return moment(a, moment.ISO_8601).format('ddd, DD/MM/YYYY hh:mm:ss');
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.getThumbnailsNames(JSON.parse(localStorage.getItem('lastWatched')));
|
||||||
|
}
|
||||||
|
|
||||||
|
// METODI
|
||||||
|
getThumbnailsNames(recentVideoList) {
|
||||||
|
let idToLookFor = recentVideoList.map(item => item.id);
|
||||||
|
axios.get('https://www.googleapis.com/youtube/v3/videos', {
|
||||||
|
params: {
|
||||||
|
part: 'snippet',
|
||||||
|
id: idToLookFor.toString(),
|
||||||
|
key: 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig',
|
||||||
|
fields: 'items(id,snippet/thumbnails/medium,snippet/title)'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
.then(
|
||||||
|
res1 => {
|
||||||
|
res1.data.items.map(resCurrentValue =>
|
||||||
|
Object.defineProperties(
|
||||||
|
recentVideoList.find(videoItem => {
|
||||||
|
return videoItem.id === resCurrentValue.id;
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
'thumbnail':
|
||||||
|
{ value: resCurrentValue.snippet.thumbnails.medium.url },
|
||||||
|
'name':
|
||||||
|
{ value: resCurrentValue.snippet.title }
|
||||||
|
})
|
||||||
|
);
|
||||||
|
this.setState({
|
||||||
|
isLoaded: true,
|
||||||
|
items: recentVideoList
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { error, isLoaded, items } = this.state;
|
||||||
|
if (error) {
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
Error: {error.message} -- Cannot get {error.config.url}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
} else if (!isLoaded) {
|
||||||
|
return <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 key={item.id} md="4">
|
||||||
|
<Card >
|
||||||
|
<Link
|
||||||
|
to={{
|
||||||
|
pathname: '/video/' + item.id,
|
||||||
|
search: "?ref=Recent"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<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>Ultima volta visto: {this.ISO_8601parse(item.lastWatched)} </span><br />
|
||||||
|
<span>Reccomender: Recent</span>
|
||||||
|
</Card.Title>
|
||||||
|
</Card.ImgOverlay>
|
||||||
|
</Link>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
</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>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export default Recent;
|
||||||
+76
-38
@@ -1,33 +1,28 @@
|
|||||||
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} from "react-bootstrap";
|
import { Card, Col, Media } from "react-bootstrap";
|
||||||
|
import moment from "moment";
|
||||||
|
|
||||||
|
|
||||||
class Related extends Component {
|
class Related extends Component {
|
||||||
constructor(props) {
|
state = {
|
||||||
super(props);
|
videoId: localStorage['lastId'],
|
||||||
this.state={
|
items: []
|
||||||
videoId : '0J2QdDbelmY',
|
|
||||||
items : []
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillMount() {
|
|
||||||
if(this.props.match.params.id){
|
ISO_8601parse(a) {
|
||||||
if(this.props.match.params.id === this.state.videoId){}
|
return moment(a, moment.ISO_8601).format('ddd, DD/MM/YYYY hh:mm:ss');
|
||||||
else{
|
|
||||||
this.setState({videoId: this.props.match.params.id});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
axios.get("https://www.googleapis.com/youtube/v3/search",{
|
axios.get("https://www.googleapis.com/youtube/v3/search", {
|
||||||
params:{
|
params: {
|
||||||
'part': 'snippet',
|
'part': 'snippet',
|
||||||
'relatedToVideoId' : this.state.videoId,
|
'relatedToVideoId': this.props.match.params.id,
|
||||||
'type' : 'video',
|
'type': 'video',
|
||||||
'maxResults' : '21',
|
'maxResults': '22',
|
||||||
'key': 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig'
|
'key': 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig'
|
||||||
}
|
}
|
||||||
}).then(
|
}).then(
|
||||||
@@ -35,7 +30,6 @@ class Related extends Component {
|
|||||||
this.setState({
|
this.setState({
|
||||||
items: response.data.items,
|
items: response.data.items,
|
||||||
})
|
})
|
||||||
console.log(response);
|
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
@@ -43,46 +37,90 @@ class Related extends Component {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUpdate(nextProps, nextState) {
|
componentDidUpdate(prevProps, prevState) {
|
||||||
if(nextProps.match.params.id === this.state.videoId){}
|
if (prevProps.match.params.id !== this.props.match.params.id) {
|
||||||
else if( nextProps.match.params.id){
|
axios.get("https://www.googleapis.com/youtube/v3/search", {
|
||||||
this.setState({videoId: nextProps.match.params.id});
|
params: {
|
||||||
|
'part': 'snippet',
|
||||||
|
'relatedToVideoId': this.props.match.params.id,
|
||||||
|
'type': 'video',
|
||||||
|
'maxResults': '22',
|
||||||
|
'key': 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig'
|
||||||
|
}
|
||||||
|
}).then(
|
||||||
|
response => {
|
||||||
|
this.setState({
|
||||||
|
items: response.data.items,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const ISO_8601parse = this.ISO_8601parse;
|
||||||
|
if (window.innerWidth < 992) {
|
||||||
return (
|
return (
|
||||||
<div style={{width: '100rem',height:'100rem'}}>
|
<React.Fragment>
|
||||||
{this.state.items.map(function (item,index) {
|
{this.state.items.map(function (item, index) {
|
||||||
return(
|
return (
|
||||||
<div key={index} style={{margin: '1rem',float: 'left'}}>
|
<Col key={index} md="4">
|
||||||
<Card>
|
<Card>
|
||||||
<Link
|
<Link
|
||||||
to={{
|
to={{
|
||||||
pathname: '/video/' + item.id.videoId,
|
pathname: '/video/' + item.id.videoId,
|
||||||
|
search: "?ref=Related"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Card.Img
|
<Card.Img
|
||||||
src={item.snippet.thumbnails.high.url}
|
src={item.snippet.thumbnails.high.url}
|
||||||
alt={'Thumbnail of ' + item.title}
|
alt={'Thumbnail of ' + item.snippet.title}
|
||||||
style={{width:'30rem',height:'20rem'}}
|
|
||||||
/>
|
/>
|
||||||
<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} - {item.snippet.publishedAt.replace(/(\d+)-(\d+)-(\d+)T(\d+):(\d+):(\d+).000Z/,function(match,p1,p2,p3,p4,p5,p6){
|
{item.snippet.channelTitle} - {ISO_8601parse(item.snippet.publishedAt)}<br />
|
||||||
return(p3+'/'+p2+'/'+p1+' at '+p4+':'+p5+':'+p6); //Funzione che trasforma la data e ora di pubblicazione dal formato ISO nel normale formato da cristiani
|
<span>Reccomender: Related</span>
|
||||||
})}
|
|
||||||
</Card.Title>
|
</Card.Title>
|
||||||
</Card.ImgOverlay>
|
</Card.ImgOverlay>
|
||||||
</Link>
|
</Link>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</Col>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</div>
|
</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 = {
|
||||||
|
|||||||
@@ -0,0 +1,170 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import axios from 'axios';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { Col, Media, Card } from 'react-bootstrap';
|
||||||
|
|
||||||
|
class Search extends React.Component {
|
||||||
|
|
||||||
|
state = {
|
||||||
|
query: '',
|
||||||
|
isLoaded: false,
|
||||||
|
error: null,
|
||||||
|
res: null
|
||||||
|
}
|
||||||
|
|
||||||
|
// static getDerivedStateFromProps(nextProps, prevState) {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
if (new RegExp("[0-9A-Za-z_-]{10}[048AEIMQUYcgkosw]").test(this.props.match.params.query.toString()))
|
||||||
|
axios.get('https://www.googleapis.com/youtube/v3/videos', {
|
||||||
|
params: {
|
||||||
|
'part': 'id',
|
||||||
|
'id': this.props.match.params.query,
|
||||||
|
'key': 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig',
|
||||||
|
'field': 'pageInfo/resultsPerPage'
|
||||||
|
}
|
||||||
|
}).then(
|
||||||
|
res => {
|
||||||
|
res.data.pageInfo.resultsPerPage ?
|
||||||
|
this.props.history.push('/video/' + this.props.match.params.query) :
|
||||||
|
this.youtubeSearch()
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
else
|
||||||
|
this.youtubeSearch();
|
||||||
|
}
|
||||||
|
|
||||||
|
// shouldComponentUpdate(nextProps, nextState) {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps, prevState) {
|
||||||
|
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: {
|
||||||
|
'part': 'id',
|
||||||
|
'id': this.props.match.params.query,
|
||||||
|
'key': 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig',
|
||||||
|
'field': 'pageInfo/resultsPerPage'
|
||||||
|
}
|
||||||
|
}).then(
|
||||||
|
res => {
|
||||||
|
res.data.pageInfo.resultsPerPage ?
|
||||||
|
this.props.history.push('/video/' + this.props.match.params.query) :
|
||||||
|
this.youtubeSearch()
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.error(error)
|
||||||
|
this.setState({
|
||||||
|
error
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
else
|
||||||
|
this.youtubeSearch();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// componentWillUnmount() {
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
youtubeSearch() {
|
||||||
|
return axios.get('https://www.googleapis.com/youtube/v3/search', {
|
||||||
|
params: {
|
||||||
|
'part': 'snippet',
|
||||||
|
'q': this.props.match.params.query,
|
||||||
|
'videoEmbeddable': 'true',
|
||||||
|
'type': 'video',
|
||||||
|
'maxResults': 30,
|
||||||
|
'topicId': '/m/04rlf, /m/02jjt',
|
||||||
|
'key': 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig'
|
||||||
|
}
|
||||||
|
}).then(
|
||||||
|
res =>
|
||||||
|
this.setState({
|
||||||
|
res: res.data,
|
||||||
|
isLoaded: true
|
||||||
|
})
|
||||||
|
,
|
||||||
|
error => this.setState({
|
||||||
|
error
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
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.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 md="4">
|
||||||
|
<Card key={item.id.videoId}>
|
||||||
|
<Link
|
||||||
|
to={{
|
||||||
|
pathname: '/video/' + item.id.videoId,
|
||||||
|
search: "?ref=Search"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Card.Img
|
||||||
|
src={item.snippet.thumbnails.medium.url}
|
||||||
|
alt={'Thumbnail of ' + item.snippet.title}
|
||||||
|
/>
|
||||||
|
<Card.ImgOverlay>
|
||||||
|
<Card.Title className="bg-dark d-inline text-white">
|
||||||
|
<p>{item.snippet.title}</p>
|
||||||
|
<p className='small'>{item.lastSelected}</p>
|
||||||
|
<p className='small'>Reccomender: Search</p>
|
||||||
|
</Card.Title>
|
||||||
|
</Card.ImgOverlay>
|
||||||
|
</Link>
|
||||||
|
</Card>
|
||||||
|
</Col>))}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Search;
|
||||||
+140
-15
@@ -1,22 +1,147 @@
|
|||||||
import React, { Component } from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
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"] }] */
|
||||||
|
|
||||||
axios.get('http://site1825.tw.cs.unibo.it/TW/globpop',
|
class fvitali extends React.Component {
|
||||||
{
|
state = {
|
||||||
id: videoID // variabile con videoid
|
error: null,
|
||||||
})
|
isLoaded: false,
|
||||||
.then(
|
items: [],
|
||||||
response => { // notazione moderna javascript per indicare function(response){}
|
};
|
||||||
// function(response){} == response => {}
|
|
||||||
console.log(response);
|
|
||||||
console.info(response.data);
|
|
||||||
|
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
axios.get('http://site1825.tw.cs.unibo.it/TW/globpop', {
|
||||||
|
'params': {
|
||||||
|
'id': this.props.match.params.id //se 'id'=>'Id', allora tutti video random, sennò anche per genere simile
|
||||||
|
}
|
||||||
|
}).then(
|
||||||
|
response => {
|
||||||
|
this.getThumbnailsNames(response.data.recommended);
|
||||||
},
|
},
|
||||||
// Note: it's important to handle errors here
|
|
||||||
// instead of a catch() block so that we don't swallow
|
|
||||||
// exceptions from actual bugs in components.
|
|
||||||
error => {
|
error => {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
this.setState({
|
||||||
|
isLoaded: true,
|
||||||
|
error
|
||||||
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// METODI
|
||||||
|
getThumbnailsNames(reccomended) {
|
||||||
|
let idToLookFor = reccomended.map(item => item.videoID);
|
||||||
|
axios.get('https://www.googleapis.com/youtube/v3/videos', {
|
||||||
|
params: {
|
||||||
|
part: 'snippet',
|
||||||
|
id: idToLookFor.toString(),
|
||||||
|
key: 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig',
|
||||||
|
fields: 'items(id,snippet/thumbnails/medium,snippet/title)'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
.then(
|
||||||
|
res1 => {
|
||||||
|
res1.data.items.map(resCurrentValue =>
|
||||||
|
Object.defineProperties(
|
||||||
|
reccomended.find(videoItem => {
|
||||||
|
return videoItem.videoID === resCurrentValue.id;
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
'thumbnail':
|
||||||
|
{ value: resCurrentValue.snippet.thumbnails.medium.url },
|
||||||
|
'name':
|
||||||
|
{ value: resCurrentValue.snippet.title }
|
||||||
|
})
|
||||||
|
);
|
||||||
|
this.setState({
|
||||||
|
isLoaded: true,
|
||||||
|
items: reccomended
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { error, isLoaded, items } = this.state;
|
||||||
|
if (error) {
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
Error: {error.message} -- Cannot get {error.config.url}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
} else if (!isLoaded) {
|
||||||
|
return (
|
||||||
|
<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.videoID}>
|
||||||
|
<Link
|
||||||
|
to={{
|
||||||
|
pathname: '/video/' + item.videoID,
|
||||||
|
search: "?ref=fvitali"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Card.Img
|
||||||
|
src={item.thumbnail}
|
||||||
|
alt={'Thumbnail of ' + item.name}
|
||||||
|
/>
|
||||||
|
<Card.ImgOverlay>
|
||||||
|
<Card.Title className="bg-dark d-inline text-white">
|
||||||
|
<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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export default fvitali;
|
export default fvitali;
|
||||||
@@ -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;
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
import React from 'react';
|
||||||
|
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 = {
|
||||||
|
error: null,
|
||||||
|
isLoaded: false,
|
||||||
|
items: [],
|
||||||
|
headers: null
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
// 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) {
|
||||||
|
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: _.uniq(idToLookFor).slice(0,50).toString(),
|
||||||
|
key: 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig',
|
||||||
|
fields: 'items(id,snippet/thumbnails/high,snippet/title)'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(
|
||||||
|
res1 => {
|
||||||
|
this.setState({
|
||||||
|
items: res1.data.items,
|
||||||
|
isLoaded: true,
|
||||||
|
});
|
||||||
|
console.log(res1)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { error, isLoaded, items } = this.state;
|
||||||
|
if (error) {
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
Error: {error.message} -- Cannot get {error.config.url}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
} else if (!isLoaded) {
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<Col>
|
||||||
|
<p className="text-center">Loading...</p>
|
||||||
|
</Col>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
} else { if (window.innerWidth < 992){
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
{items.map(item => (<Col md="4">
|
||||||
|
<Card>
|
||||||
|
<Link
|
||||||
|
to={{
|
||||||
|
pathname: '/video/' + item.videoID,
|
||||||
|
search: "?ref=popGlobaleAssoluta"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<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: popGlobaleAssoluta</span>
|
||||||
|
</Card.Title>
|
||||||
|
</Card.ImgOverlay>
|
||||||
|
</Link>
|
||||||
|
</Card>
|
||||||
|
</Col>))}
|
||||||
|
|
||||||
|
</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>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export default popGlobaleAssoluta;
|
||||||
@@ -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;
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
import React from 'react';
|
||||||
|
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"] }] */
|
||||||
|
import moment from "moment";
|
||||||
|
|
||||||
|
class PopRelLoc extends React.Component {
|
||||||
|
state = {
|
||||||
|
error: null,
|
||||||
|
isLoaded: false,
|
||||||
|
items: [],
|
||||||
|
headers: null
|
||||||
|
};
|
||||||
|
|
||||||
|
ISO_8601parse(a) {
|
||||||
|
return moment(a, moment.ISO_8601).format('ddd, DD/MM/YYYY hh:mm:ss');
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
axios.get("http://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))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// METODI
|
||||||
|
getThumbnailsNames(listVideo) {
|
||||||
|
let idToLookFor = listVideo.map(item => item.id);
|
||||||
|
axios.get('https://www.googleapis.com/youtube/v3/videos', {
|
||||||
|
params: {
|
||||||
|
part: 'snippet',
|
||||||
|
id: idToLookFor.toString(),
|
||||||
|
key: 'AIzaSyA21Odw9UdfiOJnxvA_eDfOW0OxuUfHKig',
|
||||||
|
fields: 'items(id,snippet/thumbnails/medium,snippet/title)'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
.then(
|
||||||
|
res1 => {
|
||||||
|
res1.data.items.map(resCurrentValue =>
|
||||||
|
Object.defineProperties(
|
||||||
|
listVideo.find(videoItem => {
|
||||||
|
return videoItem.id === resCurrentValue.id;
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
'thumbnail':
|
||||||
|
{ value: resCurrentValue.snippet.thumbnails.medium.url },
|
||||||
|
'name':
|
||||||
|
{ value: resCurrentValue.snippet.title }
|
||||||
|
})
|
||||||
|
);
|
||||||
|
this.setState({
|
||||||
|
isLoaded: true,
|
||||||
|
items: listVideo
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { error, isLoaded, items } = this.state;
|
||||||
|
if (error) {
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
Error: {error.message} -- Cannot get {error.config.url}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
} else if (!isLoaded) {
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<Col>
|
||||||
|
<p className="text-center">Loading...</p>
|
||||||
|
</Col>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if (window.innerWidth < 992) {
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
{items.map(item => (
|
||||||
|
<Col md="4">
|
||||||
|
<Card key={item.id}>
|
||||||
|
<Link
|
||||||
|
to={{
|
||||||
|
pathname: '/video/' + item.id,
|
||||||
|
search: "?ref=popRelLoc"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<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: popRelLoc </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,
|
||||||
|
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>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export default PopRelLoc;
|
||||||
@@ -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;
|
||||||
@@ -30,7 +30,7 @@ export default function register() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('load', () => {
|
window.addEventListener('load', () => {
|
||||||
const swUrl = `${process.env.PUBLIC_URL?process.env.PUBLIC_URL:'http://localhost:8000'}/service-worker.js`;
|
const swUrl = `${process.env.PUBLIC_URL ? process.env.PUBLIC_URL : 'http://localhost:8000'}/service-worker.js`;
|
||||||
|
|
||||||
if (isLocalhost) {
|
if (isLocalhost) {
|
||||||
// This is running on localhost. Lets check if a service worker still exists or not.
|
// This is running on localhost. Lets check if a service worker still exists or not.
|
||||||
|
|||||||
Reference in New Issue
Block a user