added front end support for optional month playlists

This commit is contained in:
aj 2019-08-18 09:43:48 +01:00
parent ebbf374ae7
commit 42e0a8c22c
3 changed files with 210 additions and 68 deletions

View File

@ -7,14 +7,13 @@ logger = logging.getLogger(__name__)
logger.setLevel('DEBUG') logger.setLevel('DEBUG')
if os.environ.get('DEPLOY_DESTINATION', None) == 'PROD': if os.environ.get('DEPLOY_DESTINATION', None) == 'PROD':
from google.cloud.logging.handlers import CloudLoggingHandler
from google.cloud import logging as glogging from google.cloud import logging as glogging
log_format = '%(funcName)s - %(message)s' log_format = '%(funcName)s - %(message)s'
formatter = logging.Formatter(log_format) formatter = logging.Formatter(log_format)
client = glogging.Client() client = glogging.Client()
handler = CloudLoggingHandler(client, name='playlist-manager') handler = client.get_default_handler()
handler.setFormatter(formatter) handler.setFormatter(formatter)

View File

@ -3,6 +3,36 @@ const axios = require('axios');
import showMessage from "../Toast.js" import showMessage from "../Toast.js"
var thisMonth = [
'january',
'february',
'march',
'april',
'may',
'june',
'july',
'august',
'septempber',
'october',
'november',
'december'
];
var lastMonth = [
'december',
'january',
'february',
'march',
'april',
'may',
'june',
'july',
'august',
'septempber',
'october',
'november'
];
class PlaylistView extends Component{ class PlaylistView extends Component{
constructor(props){ constructor(props){
@ -18,21 +48,25 @@ class PlaylistView extends Component{
day_boundary: '', day_boundary: '',
recommendation_sample: '', recommendation_sample: '',
newPlaylistName: '', newPlaylistName: '',
newPlaylistReference: '', newReferenceName: '',
shuffle: false, shuffle: false,
include_recommendations: false include_recommendations: false,
add_this_month: false,
add_last_month: false
} }
this.handleAddPart = this.handleAddPart.bind(this); this.handleAddPart = this.handleAddPart.bind(this);
this.handleAddReference = this.handleAddReference.bind(this); this.handleAddReference = this.handleAddReference.bind(this);
this.handleInputChange = this.handleInputChange.bind(this); this.handleInputChange = this.handleInputChange.bind(this);
this.handleRemoveRow = this.handleRemoveRow.bind(this); this.handleRemovePart = this.handleRemovePart.bind(this);
this.handleRemoveRefRow = this.handleRemoveRefRow.bind(this); this.handleRemoveReference = this.handleRemoveReference.bind(this);
this.handleRun = this.handleRun.bind(this); this.handleRun = this.handleRun.bind(this);
this.handleShuffleChange = this.handleShuffleChange.bind(this); this.handleShuffleChange = this.handleShuffleChange.bind(this);
this.handleRecChange = this.handleRecChange.bind(this); this.handleIncludeRecommendationsChange = this.handleIncludeRecommendationsChange.bind(this);
this.handleThisMonthChange = this.handleThisMonthChange.bind(this);
this.handleLastMonthChange = this.handleLastMonthChange.bind(this);
} }
componentDidMount(){ componentDidMount(){
@ -56,7 +90,7 @@ class PlaylistView extends Component{
this.setState(info.data); this.setState(info.data);
this.setState({ this.setState({
playlists: playlists.data.playlists, playlists: playlists.data.playlists,
newPlaylistReference: filteredPlaylists.length > 0 ? filteredPlaylists[0].name : '' newReferenceName: filteredPlaylists.length > 0 ? filteredPlaylists[0].name : ''
}); });
})) }))
.catch((error) => { .catch((error) => {
@ -82,7 +116,7 @@ class PlaylistView extends Component{
this.handleDayBoundaryChange(event.target.value); this.handleDayBoundaryChange(event.target.value);
} }
if(event.target.name == 'recommendation_sample'){ if(event.target.name == 'recommendation_sample'){
this.handleRecSampleChange(event.target.value); this.handleRecommendationsSampleChange(event.target.value);
} }
if(event.target.name == 'type'){ if(event.target.name == 'type'){
this.handleTypeChange(event.target.value); this.handleTypeChange(event.target.value);
@ -90,6 +124,12 @@ class PlaylistView extends Component{
} }
handleDayBoundaryChange(boundary) { handleDayBoundaryChange(boundary) {
if(boundary == ''){
boundary = 0;
this.setState({
day_boundary: 0
});
}
axios.post('/api/playlist', { axios.post('/api/playlist', {
name: this.state.name, name: this.state.name,
day_boundary: parseInt(boundary) day_boundary: parseInt(boundary)
@ -98,7 +138,13 @@ class PlaylistView extends Component{
}); });
} }
handleRecSampleChange(sample){ handleRecommendationsSampleChange(sample){
if(sample == ''){
sample = 0;
this.setState({
recommendation_sample: 0
});
}
axios.post('/api/playlist', { axios.post('/api/playlist', {
name: this.state.name, name: this.state.name,
recommendation_sample: parseInt(sample) recommendation_sample: parseInt(sample)
@ -128,7 +174,31 @@ class PlaylistView extends Component{
}); });
} }
handleRecChange(event) { handleThisMonthChange(event) {
this.setState({
add_this_month: event.target.checked
});
axios.post('/api/playlist', {
name: this.state.name,
add_this_month: event.target.checked
}).catch((error) => {
showMessage(`error updating add this month (${error.response.status})`);
});
}
handleLastMonthChange(event) {
this.setState({
add_last_month: event.target.checked
});
axios.post('/api/playlist', {
name: this.state.name,
add_last_month: event.target.checked
}).catch((error) => {
showMessage(`error updating add last month (${error.response.status})`);
});
}
handleIncludeRecommendationsChange(event) {
this.setState({ this.setState({
include_recommendations: event.target.checked include_recommendations: event.target.checked
}); });
@ -177,13 +247,13 @@ class PlaylistView extends Component{
handleAddReference(event){ handleAddReference(event){
if(this.state.newPlaylistReference.length != 0){ if(this.state.newReferenceName.length != 0){
var check = this.state.playlist_references.includes(this.state.newPlaylistReference); var check = this.state.playlist_references.includes(this.state.newReferenceName);
if(check == false) { if(check == false) {
var playlist_references = this.state.playlist_references.slice(); var playlist_references = this.state.playlist_references.slice();
playlist_references.push(this.state.newPlaylistReference); playlist_references.push(this.state.newReferenceName);
playlist_references.sort(function(a, b){ playlist_references.sort(function(a, b){
if(a < b) { return -1; } if(a < b) { return -1; }
@ -195,7 +265,7 @@ class PlaylistView extends Component{
this.setState({ this.setState({
playlist_references: playlist_references, playlist_references: playlist_references,
newPlaylistReference: filteredPlaylists.length > 0 ? filteredPlaylists[0].name : '' newReferenceName: filteredPlaylists.length > 0 ? filteredPlaylists[0].name : ''
}); });
axios.post('/api/playlist', { axios.post('/api/playlist', {
name: this.state.name, name: this.state.name,
@ -213,7 +283,7 @@ class PlaylistView extends Component{
} }
} }
handleRemoveRow(id, event){ handleRemovePart(id, event){
var parts = this.state.parts; var parts = this.state.parts;
parts = parts.filter(e => e !== id); parts = parts.filter(e => e !== id);
this.setState({ this.setState({
@ -232,7 +302,7 @@ class PlaylistView extends Component{
}); });
} }
handleRemoveRefRow(id, event){ handleRemoveReference(id, event){
var playlist_references = this.state.playlist_references; var playlist_references = this.state.playlist_references;
playlist_references = playlist_references.filter(e => e !== id); playlist_references = playlist_references.filter(e => e !== id);
this.setState({ this.setState({
@ -276,6 +346,8 @@ class PlaylistView extends Component{
render(){ render(){
var date = new Date();
const table = ( const table = (
<table className="app-table max-width"> <table className="app-table max-width">
<thead> <thead>
@ -283,8 +355,8 @@ class PlaylistView extends Component{
<th colSpan="2"><h1 className="text-no-select">{ this.state.name }</h1></th> <th colSpan="2"><h1 className="text-no-select">{ this.state.name }</h1></th>
</tr> </tr>
</thead> </thead>
{ this.state.playlist_references.length > 0 && <ListBlock name="managed" handler={this.handleRemoveRefRow} list={this.state.playlist_references}/> } { this.state.playlist_references.length > 0 && <ListBlock name="managed" handler={this.handleRemoveReference} list={this.state.playlist_references}/> }
{ this.state.parts.length > 0 && <ListBlock name="spotify" handler={this.handleRemoveRow} list={this.state.parts}/> } { this.state.parts.length > 0 && <ListBlock name="spotify" handler={this.handleRemovePart} list={this.state.parts}/> }
<tbody> <tbody>
<tr> <tr>
<td colSpan="2" className="center-text ui-text text-no-select" style={{fontStyle: "italic"}}> <td colSpan="2" className="center-text ui-text text-no-select" style={{fontStyle: "italic"}}>
@ -306,9 +378,9 @@ class PlaylistView extends Component{
</tr> </tr>
<tr> <tr>
<td> <td>
<select name="newPlaylistReference" <select name="newReferenceName"
className="full-width" className="full-width"
value={this.state.newPlaylistReference} value={this.state.newReferenceName}
onChange={this.handleInputChange}> onChange={this.handleInputChange}>
{ this.state.playlists { this.state.playlists
.filter((entry) => entry.name != this.state.name) .filter((entry) => entry.name != this.state.name)
@ -336,7 +408,7 @@ class PlaylistView extends Component{
<td> <td>
<input type="checkbox" <input type="checkbox"
checked={this.state.include_recommendations} checked={this.state.include_recommendations}
onChange={this.handleRecChange}></input> onChange={this.handleIncludeRecommendationsChange}></input>
</td> </td>
</tr> </tr>
<tr> <tr>
@ -365,6 +437,30 @@ class PlaylistView extends Component{
</td> </td>
</tr> </tr>
} }
{ this.state.type == 'recents' &&
<tr>
<td className="center-text ui-text text-no-select">
include {thisMonth[date.getMonth()]} playlist
</td>
<td>
<input type="checkbox"
checked={this.state.add_this_month}
onChange={this.handleThisMonthChange}></input>
</td>
</tr>
}
{ this.state.type == 'recents' &&
<tr>
<td className="center-text ui-text text-no-select">
include {lastMonth[date.getMonth()]} playlist
</td>
<td>
<input type="checkbox"
checked={this.state.add_last_month}
onChange={this.handleLastMonthChange}></input>
</td>
</tr>
}
<tr> <tr>
<td className="center-text ui-text text-no-select"> <td className="center-text ui-text text-no-select">
playlist type playlist type
@ -379,15 +475,6 @@ class PlaylistView extends Component{
</select> </select>
</td> </td>
</tr> </tr>
{ this.state.type == 'recents' &&
<tr>
<td colSpan="2" className="center-text ui-text text-no-select" style={{fontStyle: "italic"}}>
<br></br>'recents' playlists search for and include this months and last months playlists when named in the format
<br></br>[month] [year]
<br></br>e.g july 19 (lowercase)
</td>
</tr>
}
<tr> <tr>
<td colSpan="2"> <td colSpan="2">
<button className="button full-width" onClick={this.handleRun}>run</button> <button className="button full-width" onClick={this.handleRun}>run</button>

View File

@ -3,6 +3,36 @@ const axios = require('axios');
import showMessage from "../Toast.js" import showMessage from "../Toast.js"
var thisMonth = [
'january',
'february',
'march',
'april',
'may',
'june',
'july',
'august',
'septempber',
'october',
'november',
'december'
];
var lastMonth = [
'december',
'january',
'february',
'march',
'april',
'may',
'june',
'july',
'august',
'septempber',
'october',
'november'
];
class ScratchView extends Component{ class ScratchView extends Component{
constructor(props){ constructor(props){
@ -18,21 +48,25 @@ class ScratchView extends Component{
day_boundary: 5, day_boundary: 5,
recommendation_sample: 5, recommendation_sample: 5,
newPlaylistName: '', newPlaylistName: '',
newPlaylistReference: '', newReferenceName: '',
shuffle: false, shuffle: false,
include_recommendations: false include_recommendations: false,
add_this_month: false,
add_last_month: false
} }
this.handleAddPart = this.handleAddPart.bind(this); this.handleAddPart = this.handleAddPart.bind(this);
this.handleAddReference = this.handleAddReference.bind(this); this.handleAddReference = this.handleAddReference.bind(this);
this.handleInputChange = this.handleInputChange.bind(this); this.handleInputChange = this.handleInputChange.bind(this);
this.handleRemoveRow = this.handleRemoveRow.bind(this); this.handleRemovePart = this.handleRemovePart.bind(this);
this.handleRemoveRefRow = this.handleRemoveRefRow.bind(this); this.handleRemoveReference = this.handleRemoveReference.bind(this);
this.handleRun = this.handleRun.bind(this); this.handleRun = this.handleRun.bind(this);
this.handleShuffleChange = this.handleShuffleChange.bind(this); this.handleShuffleChange = this.handleShuffleChange.bind(this);
this.handleRecChange = this.handleRecChange.bind(this); this.handleIncludeRecommendationsChange = this.handleIncludeRecommendationsChange.bind(this);
this.handleThisMonthChange = this.handleThisMonthChange.bind(this);
this.handleLastMonthChange = this.handleLastMonthChange.bind(this);
} }
componentDidMount(){ componentDidMount(){
@ -48,7 +82,7 @@ class ScratchView extends Component{
this.setState({ this.setState({
playlists: response.data.playlists, playlists: response.data.playlists,
newPlaylistReference: filteredPlaylists.length > 0 ? filteredPlaylists[0].name : '' newReferenceName: filteredPlaylists.length > 0 ? filteredPlaylists[0].name : ''
}); });
}) })
.catch((error) => { .catch((error) => {
@ -62,22 +96,25 @@ class ScratchView extends Component{
}); });
} }
handleTypeChange(sample){
axios.post('/api/playlist', {
name: this.state.name,
type: sample
}).catch((error) => {
showMessage(`error updating type (${error.response.status})`);
});
}
handleShuffleChange(event) { handleShuffleChange(event) {
this.setState({ this.setState({
shuffle: event.target.checked shuffle: event.target.checked
}); });
} }
handleRecChange(event) { handleThisMonthChange(event) {
this.setState({
add_this_month: event.target.checked
});
}
handleLastMonthChange(event) {
this.setState({
add_last_month: event.target.checked
});
}
handleIncludeRecommendationsChange(event) {
this.setState({ this.setState({
include_recommendations: event.target.checked include_recommendations: event.target.checked
}); });
@ -114,13 +151,13 @@ class ScratchView extends Component{
handleAddReference(event){ handleAddReference(event){
if(this.state.newPlaylistReference.length != 0){ if(this.state.newReferenceName.length != 0){
var check = this.state.playlist_references.includes(this.state.newPlaylistReference); var check = this.state.playlist_references.includes(this.state.newReferenceName);
if(check == false) { if(check == false) {
var playlist_references = this.state.playlist_references.slice(); var playlist_references = this.state.playlist_references.slice();
playlist_references.push(this.state.newPlaylistReference); playlist_references.push(this.state.newReferenceName);
playlist_references.sort(function(a, b){ playlist_references.sort(function(a, b){
if(a < b) { return -1; } if(a < b) { return -1; }
@ -132,7 +169,7 @@ class ScratchView extends Component{
this.setState({ this.setState({
playlist_references: playlist_references, playlist_references: playlist_references,
newPlaylistReference: filteredPlaylists.length > 0 ? filteredPlaylists[0].name : '' newReferenceName: filteredPlaylists.length > 0 ? filteredPlaylists[0].name : ''
}); });
}else{ }else{
@ -144,7 +181,7 @@ class ScratchView extends Component{
} }
} }
handleRemoveRow(id, event){ handleRemovePart(id, event){
var parts = this.state.parts; var parts = this.state.parts;
parts = parts.filter(e => e !== id); parts = parts.filter(e => e !== id);
this.setState({ this.setState({
@ -156,7 +193,7 @@ class ScratchView extends Component{
} }
} }
handleRemoveRefRow(id, event){ handleRemoveReference(id, event){
var playlist_references = this.state.playlist_references; var playlist_references = this.state.playlist_references;
playlist_references = playlist_references.filter(e => e !== id); playlist_references = playlist_references.filter(e => e !== id);
this.setState({ this.setState({
@ -176,7 +213,9 @@ class ScratchView extends Component{
include_recommendations: this.state.include_recommendations, include_recommendations: this.state.include_recommendations,
recommendation_sample: this.state.recommendation_sample, recommendation_sample: this.state.recommendation_sample,
day_boundary: this.state.day_boundary, day_boundary: this.state.day_boundary,
playlist_type: this.state.type playlist_type: this.state.type,
add_this_month: this.state.add_this_month,
add_last_month: this.state.add_last_month
}) })
.then((reponse) => { .then((reponse) => {
showMessage(`played`); showMessage(`played`);
@ -197,6 +236,8 @@ class ScratchView extends Component{
render(){ render(){
var date = new Date();
const table = ( const table = (
<table className="app-table max-width"> <table className="app-table max-width">
{/* <thead> {/* <thead>
@ -204,8 +245,8 @@ class ScratchView extends Component{
<th colSpan="2"><h1 className="text-no-select">{ this.state.name }</h1></th> <th colSpan="2"><h1 className="text-no-select">{ this.state.name }</h1></th>
</tr> </tr>
</thead> */} </thead> */}
{ this.state.playlist_references.length > 0 && <ListBlock name="managed" handler={this.handleRemoveRefRow} list={this.state.playlist_references}/> } { this.state.playlist_references.length > 0 && <ListBlock name="managed" handler={this.handleRemoveReference} list={this.state.playlist_references}/> }
{ this.state.parts.length > 0 && <ListBlock name="spotify" handler={this.handleRemoveRow} list={this.state.parts}/> } { this.state.parts.length > 0 && <ListBlock name="spotify" handler={this.handleRemovePart} list={this.state.parts}/> }
<tbody> <tbody>
<tr> <tr>
<td colSpan="2" className="center-text ui-text text-no-select" style={{fontStyle: "italic"}}> <td colSpan="2" className="center-text ui-text text-no-select" style={{fontStyle: "italic"}}>
@ -227,9 +268,9 @@ class ScratchView extends Component{
</tr> </tr>
<tr> <tr>
<td> <td>
<select name="newPlaylistReference" <select name="newReferenceName"
className="full-width" className="full-width"
value={this.state.newPlaylistReference} value={this.state.newReferenceName}
onChange={this.handleInputChange}> onChange={this.handleInputChange}>
{ this.state.playlists { this.state.playlists
.filter((entry) => entry.name != this.state.name) .filter((entry) => entry.name != this.state.name)
@ -259,7 +300,7 @@ class ScratchView extends Component{
<input type="checkbox" <input type="checkbox"
name="include_recommendations" name="include_recommendations"
checked={this.state.include_recommendations} checked={this.state.include_recommendations}
onChange={this.handleRecChange}></input> onChange={this.handleIncludeRecommendationsChange}></input>
</td> </td>
</tr> </tr>
<tr> <tr>
@ -288,6 +329,30 @@ class ScratchView extends Component{
</td> </td>
</tr> </tr>
} }
{ this.state.type == 'recents' &&
<tr>
<td className="center-text ui-text text-no-select">
include {thisMonth[date.getMonth()]} playlist
</td>
<td>
<input type="checkbox"
checked={this.state.add_this_month}
onChange={this.handleThisMonthChange}></input>
</td>
</tr>
}
{ this.state.type == 'recents' &&
<tr>
<td className="center-text ui-text text-no-select">
include {lastMonth[date.getMonth()]} playlist
</td>
<td>
<input type="checkbox"
checked={this.state.add_last_month}
onChange={this.handleLastMonthChange}></input>
</td>
</tr>
}
<tr> <tr>
<td className="center-text ui-text text-no-select"> <td className="center-text ui-text text-no-select">
playlist type playlist type
@ -302,15 +367,6 @@ class ScratchView extends Component{
</select> </select>
</td> </td>
</tr> </tr>
{ this.state.type == 'recents' &&
<tr>
<td colSpan="2" className="center-text ui-text text-no-select" style={{fontStyle: "italic"}}>
<br></br>'recents' playlists search for and include this months and last months playlists when named in the format
<br></br>[month] [year]
<br></br>e.g july 19 (lowercase)
</td>
</tr>
}
<tr> <tr>
<td colSpan="2"> <td colSpan="2">
<button className="button full-width" onClick={this.handleRun}>play</button> <button className="button full-width" onClick={this.handleRun}>play</button>