Compare commits

...

3 Commits

Author SHA1 Message Date
Martyn 705b1f5e12 Allow for reload in caching
continuous-integration/drone/push Build is passing Details
Signed-off-by: Martyn Ranyard <m@rtyn.berlin>
2020-08-03 00:32:33 +02:00
Martyn f721c91690 Actual data from my account
Signed-off-by: Martyn Ranyard <m@rtyn.berlin>
2020-08-03 00:30:28 +02:00
Martyn f49d3ec9ab Cache refresh may work, local testing easier
Signed-off-by: Martyn Ranyard <m@rtyn.berlin>
2020-08-02 17:07:59 +02:00
8 changed files with 3425 additions and 12843 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -25,3 +25,18 @@
.App-menu { .App-menu {
max-width: 98%; max-width: 98%;
} }
.Footer {
max-width: 98%;
background-color: #6207a4 !important;
}
.Footer a {
color: white;
font-weight: bold;
}
.FooterCell {
border: none !important;
color: white !important;
}

View File

@ -1,9 +1,8 @@
import React from 'react'; import React from 'react';
import logo from './../../logo.svg'; import logo from './../../logo.svg';
import './App.css'; import './App.css';
import Container from '@material-ui/core/Container';
import Typography from '@material-ui/core/Typography'; import Typography from '@material-ui/core/Typography';
import { Button, Paper } from '@material-ui/core'; import { Button, Paper, Container, AppBar, Table, TableBody, TableCell, TableContainer, TableRow } from '@material-ui/core';
function App() { function App() {
const client_id = "sau3e70wvs369jw1u25ex8g3cve599" const client_id = "sau3e70wvs369jw1u25ex8g3cve599"
@ -44,6 +43,22 @@ function App() {
<Typography component="p" gutterBottom> <Typography component="p" gutterBottom>
...Coming "Soon"(tm) ...Coming "Soon"(tm)
</Typography> </Typography>
<AppBar position="static" className="Footer">
<TableContainer component={Container}>
<Table><TableBody>
<TableRow className="FooterRow">
<TableCell className="FooterCell"><a href="https://discord.gg/sVgZeRt">Discord</a></TableCell>
<TableCell className="FooterCell"><a href="https://git.martyn.berlin/martyn/twitchsingstools">Source Code</a></TableCell>
<TableCell className="FooterCell"><a href="https://twitch.tv/iMartynOnTwitch">Martyn's Twitch</a></TableCell>
</TableRow>
<TableRow className="FooterRow">
<TableCell className="FooterCell">Announcements, Support, Optional notifications</TableCell>
<TableCell className="FooterCell">Geek out at the really hacky source code from an SRE type person</TableCell>
<TableCell className="FooterCell">Streaming and singing is my hobby, not my job, so only if you want to...</TableCell>
</TableRow>
</TableBody></Table>
</TableContainer>
</AppBar>
</Paper> </Paper>
</Container> </Container>
); );

View File

@ -26,3 +26,18 @@
.App-menu { .App-menu {
max-width: 98%; max-width: 98%;
} }
.Footer {
max-width: 98%;
background-color: #6207a4 !important;
}
.Footer a {
color: white;
font-weight: bold;
}
.FooterCell {
border: none !important;
color: white !important;
}

View File

@ -7,6 +7,8 @@ import Typography from '@material-ui/core/Typography';
import TopTenSongs from "../TopTenSongs/TopTenSongs"; import TopTenSongs from "../TopTenSongs/TopTenSongs";
import TopTenSingers from "../TopTenSingers/TopTenSingers"; import TopTenSingers from "../TopTenSingers/TopTenSingers";
import DuetData from "../DuetData/DuetData"; import DuetData from "../DuetData/DuetData";
import CacheDeets from "../CacheDeets/CacheDeets";
import BotDeets from "../BotDeets/BotDeets";
import { Table, TableBody, TableCell, TableContainer, TableHead, TableRow } from '@material-ui/core'; import { Table, TableBody, TableCell, TableContainer, TableHead, TableRow } from '@material-ui/core';
import ProblemContainer from "../ProblemContainer/ProblemContainer"; import ProblemContainer from "../ProblemContainer/ProblemContainer";
@ -40,82 +42,159 @@ function a11yProps(index) {
}; };
} }
function AppAdmin() { class AppAdmin extends React.Component {
const [page, setPage] = React.useState(0); constructor(props) {
if ( super(props);
(window.location.href.split("/").length < 6) || this.setPage = this.setPage.bind(this);
(window.location.href.split("/")[3].search(/^admin/) < 0) || this.reloadSongComponent = this.reloadSongComponent.bind(this);
(window.location.href.split("/")[5].length !== 48) this.reloadSingersComponent = this.reloadSingersComponent.bind(this);
) { this.reloadDuetComponent = this.reloadDuetComponent.bind(this);
this.state = {
page: 0,
reloadSongComponent: false,
reloadSingersComponent: false,
reloadDuetComponent: false,
};
}
setPage(pageNum) {
let newState = this.state;
newState.page = pageNum;
this.setState(newState);
}
reloadSongComponent(components) {
let newState = this.state;
newState.reloadComponents = components;
this.setState(newState);
}
reloadSingersComponent(components) {
let newState = this.state;
newState.reloadComponents = components;
this.setState(newState);
}
reloadDuetComponent(components) {
let newState = this.state;
newState.reloadDuetComponent = components;
console.log("I'm trying!")
this.setState(newState);
}
render() {
const page = this.state.page
if (
(window.location.href.split("/").length < 6) ||
(window.location.href.split("/")[3].search(/^admin/) < 0) ||
(window.location.href.split("/")[5].length !== 48)
) {
if (window.location.href.split("/")[2] !== "192.168.1.111:3000") {
return (
<ProblemContainer />
)
}
}
const channelName = window.location.href.split("/")[4]
const adminToken = window.location.href.split("/")[5]
const csvURL = "/csv/"+ channelName + "/" + adminToken
const tsvURL = "/tsv/"+ channelName + "/" + adminToken
const setPage = this.setPage
const reloadDuetComponent = this.state.reloadDuetComponent
const reloadSongComponent = this.state.reloadSongComponent
const reloadSingersComponent = this.state.reloadSingersComponent
function handleChange(event, newValue) {
setPage(newValue);
}
return ( return (
<ProblemContainer /> <Container className="App">
) <Paper>
} <img src={logo} className="App-logo" alt="logo" />
<Typography variant="h4" component="h1" gutterBottom>
Twitch Sings Tools
</Typography>
<AppBar position="static" className="App-menu">
<Tabs value={page} onChange={handleChange} aria-label="simple tabs example">
<Tab label="Top Songs" {...a11yProps(0)}/>
<Tab label="Top Singers" {...a11yProps(1)}/>
<Tab label="Data" {...a11yProps(2)}/>
<Tab label="Export" {...a11yProps(3)}/>
<Tab label="Cache Details" {...a11yProps(4)}/>
<Tab label="Chatbot" {...a11yProps(4)}/>
</Tabs>
</AppBar>
<TabPanel value={page} index={0}>
<TopTenSongs reloadSongComponent={reloadSongComponent}
onReloadedChange={this.reloadSongComponent}/>
</TabPanel>
<TabPanel value={page} index={1}>
<TopTenSingers reloadSingersComponent={reloadSingersComponent}
onReloadedChange={this.reloadSingersComponent}/>
</TabPanel>
<TabPanel value={page} index={2}>
<DuetData reloadDuetComponent={reloadDuetComponent}
onReloadedChange={this.reloadDuetComponent}/>
</TabPanel>
<TabPanel value={page} index={3}>
<Typography variant="h5" component="h2" gutterBottom>
Download your data as :
</Typography>
<TableContainer component={Paper}>
<Table>
<TableHead>
<TableRow>
<TableCell>TSV</TableCell>
<TableCell>CSV</TableCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow>
<TableCell><a href={tsvURL}>here</a></TableCell>
<TableCell><a href={csvURL}>here</a></TableCell>
</TableRow>
</TableBody>
</Table>
</TableContainer>
<Typography variant="h5" component="h2" gutterBottom>
Note: Excel is not very good at handling CSV format it seems...
</Typography>
<Typography component="p" gutterBottom>It is important to "Import Data" not "Open" the csv in many cases (8 year old discussion of this behaviour <a href="https://superuser.com/questions/407082/easiest-way-to-open-csv-with-commas-in-excel">here</a>) - from that post the instructions are :</Typography>
<Typography component="q" gutterBottom>In Excel, DATA tab, in the Get External Data subsection, click "From Text" and import your CSV in the Wizard.</Typography>
<Typography component="p" gutterBottom>LibreOffice calc kinda just works...just sayin' ;-)</Typography>
const channelName = window.location.href.split("/")[4] </TabPanel>
const adminToken = window.location.href.split("/")[5] <TabPanel value={page} index={4}>
const csvURL = "/csv/"+ channelName + "/" + adminToken <CacheDeets
const tsvURL = "/tsv/"+ channelName + "/" + adminToken onReloadSongsChange={this.reloadSongComponent}
onReloadSingersChange={this.reloadSingersComponent}
function handleChange(event, newValue) { onReloadDuetChange={this.reloadDuetComponent}
setPage(newValue); />
} </TabPanel>
<TabPanel value={page} index={5}>
return ( <BotDeets />
<Container className="App"> </TabPanel>
<Paper> <AppBar position="static" className="Footer">
<img src={logo} className="App-logo" alt="logo" /> <TableContainer component={Container}>
<Typography variant="h4" component="h1" gutterBottom> <Table><TableBody>
Twitch Sings Tools <TableRow className="FooterRow">
</Typography> <TableCell className="FooterCell"><a href="https://discord.gg/sVgZeRt">Discord</a></TableCell>
<AppBar position="static" className="App-menu"> <TableCell className="FooterCell"><a href="https://git.martyn.berlin/martyn/twitchsingstools">Source Code</a></TableCell>
<Tabs value={page} onChange={handleChange} aria-label="simple tabs example"> <TableCell className="FooterCell"><a href="https://twitch.tv/iMartynOnTwitch">Martyn's Twitch</a></TableCell>
<Tab label="Top Songs" {...a11yProps(0)}/>
<Tab label="Top Singers" {...a11yProps(1)}/>
<Tab label="Data" {...a11yProps(2)}/>
<Tab label="Export" {...a11yProps(3)}/>
</Tabs>
</AppBar>
<TabPanel value={page} index={0}>
<TopTenSongs />
</TabPanel>
<TabPanel value={page} index={1}>
<TopTenSingers />
</TabPanel>
<TabPanel value={page} index={2}>
<DuetData />
</TabPanel>
<TabPanel value={page} index={3}>
<Typography variant="h5" component="h2" gutterBottom>
Download your data as :
</Typography>
<TableContainer component={Paper}>
<Table>
<TableHead>
<TableRow>
<TableCell>TSV</TableCell>
<TableCell>CSV</TableCell>
</TableRow> </TableRow>
</TableHead> <TableRow className="FooterRow">
<TableBody> <TableCell className="FooterCell">Announcements, Support, Optional notifications</TableCell>
<TableRow> <TableCell className="FooterCell">Geek out at the really hacky source code from an SRE type person</TableCell>
<TableCell><a href={tsvURL}>here</a></TableCell> <TableCell className="FooterCell">Streaming and singing is my hobby, not my job, so only if you want to...</TableCell>
<TableCell><a href={csvURL}>here</a></TableCell>
</TableRow> </TableRow>
</TableBody> </TableBody></Table>
</Table> </TableContainer>
</TableContainer> </AppBar>
<Typography variant="h5" component="h2" gutterBottom> </Paper>
Note: Excel is not very good at handling CSV format it seems... </Container>
</Typography> );
<Typography component="p" gutterBottom>It is important to "Import Data" not "Open" the csv in many cases (8 year old discussion of this behaviour <a href="https://superuser.com/questions/407082/easiest-way-to-open-csv-with-commas-in-excel">here</a>) - from that post the instructions are :</Typography> }
<Typography component="q" gutterBottom>In Excel, DATA tab, in the Get External Data subsection, click "From Text" and import your CSV in the Wizard.</Typography>
<Typography component="p" gutterBottom>LibreOffice calc kinda just works...just sayin' ;-)</Typography>
</TabPanel>
</Paper>
</Container>
);
} }
export default AppAdmin; export default AppAdmin;

View File

@ -0,0 +1,53 @@
import React, { useEffect } from 'react';
import { Container, Typography, Button } from '@material-ui/core';
const channelName = window.location.href.split("/")[4]
const adminToken = window.location.href.split("/")[5]
const dataURL = "/botdeets/"+ channelName + "/" + adminToken
function BotDeets() {
const [botState, setBotState] = React.useState({loading: true, botData: []})
useEffect(() => {
// We should only fetch once!
if (botState.loading) {
fetch(dataURL).then((res) => res.json().then((data)=>{
setBotState({botData: data, loading: false })
}));
}
}, [setBotState, botState.loading]);
if (botState.loading) {
return <p>Sorry, still loading...</p>
}
let dd = botState.botData
if (dd.hasleft) {
return (
<Container>
<Typography variant="h5" component="h2" gutterBottom>
The chatbot is currently <b>not</b> in your channel. To change the settings, invite it to your channel using the button below :
</Typography>
<Typography variant="p">
You really don't wanna do that, because it's not ready yet.
</Typography>
<Typography variant="p">
<Button variant="contained" color="primary">Join my channel!</Button>
</Typography>
</Container>
)
} else {
return (
<Container>
<Typography variant="h5" component="h2" gutterBottom>
Coming soon! Bot control panel!
</Typography>
<Typography component="tt" gutterBottom>
{dd}
</Typography>
</Container>
);
}
}
export default BotDeets;

View File

@ -0,0 +1,81 @@
import React from 'react';
import { Container, Typography, Button } from '@material-ui/core';
const channelName = window.location.href.split("/")[4]
const adminToken = window.location.href.split("/")[5]
const dataURL = "/cachedeets/"+ channelName + "/" + adminToken
const forceURL = "/force/"+ channelName + "/" + adminToken
class CacheDeets extends React.Component {
constructor(props) {
super(props);
this.state = {
cacheData: [],
loading: true
};
this.setCacheData = this.setCacheData.bind(this);
this.setLoading = this.setLoading.bind(this);
}
setCacheData(data) {
let newState = this.state
newState.cacheData = data
this.setState(newState)
}
setLoading(data) {
let newState = this.state
newState.loading = data
this.setState(newState)
}
componentDidMount() {
// We should only fetch once!
if (this.state.loading) {
let actualURL = dataURL
if (window.location.href.split("/")[2] === "192.168.1.111:3000") {
//Frontend dev mode only
actualURL = "/sampleData/cache.json"
}
fetch(actualURL).then((res) => res.json().then((data)=>{
this.setLoading(false)
this.setCacheData(data)
}));
}
}
render() {
const loading = this.state.loading
const setLoading = this.setLoading
const cacheData = this.state.cacheData
function handleClick(e) {
setLoading(true)
fetch(forceURL).then((data)=>{
setLoading(false)
window.location.reload()
})
console.log('The link was clicked.');
}
if (loading) {
return <p>Sorry, still loading...</p>
}
let dd = cacheData
return (
<Container>
<Typography variant="h5" component="h2" gutterBottom>
Server has cached data from <b>{dd.SongCount} published</b> performances
</Typography>
<Typography component="p" gutterBottom>
Cache data is from about {dd.AgeStr} - it automatically gets updated if it's older than an hour. If you're convinced using Martyn's bandwidth to refresh the cache earlier than that is worth it, here's the button below :
</Typography>
<Button variant="contained" color="primary" onClick={handleClick}>Force refresh cache</Button>
</Container>
);
}
}
export default CacheDeets;