added open in tag UI, added include_spotify_owned

This commit is contained in:
andy 2021-07-10 16:00:30 +01:00
parent 79c841d9d8
commit 365cafe004
4 changed files with 75 additions and 10 deletions

View File

@ -54,6 +54,8 @@ class Playlist(Model):
add_this_month = BooleanField(default=False) add_this_month = BooleanField(default=False)
day_boundary = NumberField(default=21) day_boundary = NumberField(default=21)
include_spotify_owned = BooleanField(default=True)
chart_range = TextField(default='MONTH') chart_range = TextField(default='MONTH')
chart_limit = NumberField(default=50) chart_limit = NumberField(default=50)

View File

@ -89,3 +89,11 @@ class User(Model):
return matches[0] return matches[0]
else: else:
return exact_match, matches return exact_match, matches
def get_playlists(self):
"""Get all playlists for a user
Returns:
List[Playlist]: List of users playlists
"""
return Playlist.collection.parent(self.key).fetch()

View File

@ -77,7 +77,10 @@ def run_user_playlist(user: User, playlist: Playlist, spotnet: SpotNetwork = Non
raise NameError(f'No Spotify network returned ({username} / {playlist_name})') raise NameError(f'No Spotify network returned ({username} / {playlist_name})')
try: try:
user_playlists = [(i.name, i.uri) for i in spotnet.playlists()] if not playlist.include_spotify_owned:
user_playlists = [(i.name, i.uri) for i in spotnet.playlists() if 'spotify' not in i.owner.display_name.lower()]
else:
user_playlists = [(i.name, i.uri) for i in spotnet.playlists()]
except SpotifyNetworkException as e: except SpotifyNetworkException as e:
logger.exception(f'error occured while retrieving playlists {username} / {playlist_name}') logger.exception(f'error occured while retrieving playlists {username} / {playlist_name}')
raise e raise e

View File

@ -1,8 +1,8 @@
import React, { Component } from "react"; import React, { Component } from "react";
const axios = require('axios'); const axios = require('axios');
import { Card, Button, CardActions, CardContent, FormControl, InputLabel, Select, Typography, Grid, TextField, MenuItem, FormControlLabel, Switch } from '@material-ui/core'; import { Card, Button, ButtonGroup, CardActions, CardContent, FormControl, InputLabel, Select, Typography, Grid, TextField, MenuItem, FormControlLabel, Switch } from '@material-ui/core';
import { Delete } from '@material-ui/icons'; import { Delete, ExitToApp } from '@material-ui/icons';
import { makeStyles } from '@material-ui/core/styles'; import { makeStyles } from '@material-ui/core/styles';
import showMessage from "../Toast.js"; import showMessage from "../Toast.js";
@ -28,6 +28,7 @@ class TagView extends Component{
super(props); super(props);
this.state = { this.state = {
tag_id: props.match.params.tag_id, tag_id: props.match.params.tag_id,
username: null,
tag: { tag: {
name: "", name: "",
tracks: [], tracks: [],
@ -44,6 +45,7 @@ class TagView extends Component{
} }
this.handleInputChange = this.handleInputChange.bind(this); this.handleInputChange = this.handleInputChange.bind(this);
this.handleRun = this.handleRun.bind(this); this.handleRun = this.handleRun.bind(this);
this.handleView = this.handleView.bind(this);
this.handleRemoveObj = this.handleRemoveObj.bind(this); this.handleRemoveObj = this.handleRemoveObj.bind(this);
this.handleCheckChange = this.handleCheckChange.bind(this); this.handleCheckChange = this.handleCheckChange.bind(this);
@ -58,6 +60,7 @@ class TagView extends Component{
*/ */
componentDidMount(){ componentDidMount(){
this.getTag(); this.getTag();
this.getUserInfo();
// var intervalId = setInterval(() => {this.getTag(false)}, 5000); // var intervalId = setInterval(() => {this.getTag(false)}, 5000);
// var timeoutId = setTimeout(() => {clearInterval(this.state.intervalId)}, 300000); // var timeoutId = setTimeout(() => {clearInterval(this.state.intervalId)}, 300000);
@ -72,6 +75,26 @@ class TagView extends Component{
// clearTimeout(this.state.timeoutId); // clearTimeout(this.state.timeoutId);
// } // }
/**
* Get user info from API
*/
getUserInfo(){
this.userInfoCancelToken = axios.CancelToken.source();
var self = this;
axios.get('/api/user', {
cancelToken: this.userInfoCancelToken.token
})
.then((response) => {
self.setState({
username: response.data.lastfm_username
})
})
.catch((error) => {
showMessage(`error getting user info (${error.response.status})`);
});
}
/** /**
* Get tag info from API * Get tag info from API
* @param {*} error_toast Whether to show toast on network error * @param {*} error_toast Whether to show toast on network error
@ -173,6 +196,30 @@ class TagView extends Component{
}); });
} }
/**
* Open a tag element in Last.fm
* @param {*} music_obj Tag element to be viewed
* @param {*} addType Tag type, artist, album etc
* @param {*} event
*/
handleView(music_obj, addType, event){
let url = `https://last.fm/user/${this.state.username}/library/music/`;
switch(addType) {
case "artists":
url = url + encodeURI(music_obj.name);
break;
case "albums":
url = `${url}${encodeURI(music_obj.artist)}/${encodeURI(music_obj.name)}`;
break;
case "tracks":
url = `${url}${encodeURI(music_obj.artist)}/_/${encodeURI(music_obj.name)}`;
break;
}
window.open(url);
}
/** /**
* Handle remove watched part * Handle remove watched part
* @param {*} music_obj Subject object to remove * @param {*} music_obj Subject object to remove
@ -334,17 +381,17 @@ class TagView extends Component{
{/* ARTISTS TITLE */} {/* ARTISTS TITLE */}
{ this.state.tag.artists.length > 0 && <Grid item xs={12} ><Typography color="textSecondary" variant="h4">Artists</Typography></Grid> } { this.state.tag.artists.length > 0 && <Grid item xs={12} ><Typography color="textSecondary" variant="h4">Artists</Typography></Grid> }
{/* ARTIST CARDS */} {/* ARTIST CARDS */}
{ this.state.tag.artists.length > 0 && <ListBlock handler={this.handleRemoveObj} list={this.state.tag.artists} addType="artists" showTime={this.state.tag.time_objects}/> } { this.state.tag.artists.length > 0 && <ListBlock viewHandler={this.handleView} deleteHandler={this.handleRemoveObj} list={this.state.tag.artists} addType="artists" showTime={this.state.tag.time_objects}/> }
{/* ALBUMS TITLE */} {/* ALBUMS TITLE */}
{ this.state.tag.albums.length > 0 && <Grid item xs={12} ><Typography color="textSecondary" variant="h4">Albums</Typography></Grid> } { this.state.tag.albums.length > 0 && <Grid item xs={12} ><Typography color="textSecondary" variant="h4">Albums</Typography></Grid> }
{/* ALBUM CARDS */} {/* ALBUM CARDS */}
{ this.state.tag.albums.length > 0 && <ListBlock handler={this.handleRemoveObj} list={this.state.tag.albums} addType="albums" showTime={this.state.tag.time_objects}/> } { this.state.tag.albums.length > 0 && <ListBlock viewHandler={this.handleView} deleteHandler={this.handleRemoveObj} list={this.state.tag.albums} addType="albums" showTime={this.state.tag.time_objects}/> }
{/* TRACKS TITLE */} {/* TRACKS TITLE */}
{ this.state.tag.tracks.length > 0 && <Grid item xs={12} ><Typography color="textSecondary" variant="h4">Tracks</Typography></Grid> } { this.state.tag.tracks.length > 0 && <Grid item xs={12} ><Typography color="textSecondary" variant="h4">Tracks</Typography></Grid> }
{/* TRACK CARDS */} {/* TRACK CARDS */}
{ this.state.tag.tracks.length > 0 && <ListBlock handler={this.handleRemoveObj} list={this.state.tag.tracks} addType="tracks" showTime={this.state.tag.time_objects}/> } { this.state.tag.tracks.length > 0 && <ListBlock viewHandler={this.handleView} deleteHandler={this.handleRemoveObj} list={this.state.tag.tracks} addType="tracks" showTime={this.state.tag.time_objects}/> }
{/* NAME TEXTBOX */} {/* NAME TEXTBOX */}
<Grid item xs={12} sm={this.state.addType != 'artists' ? 3 : 4} md={this.state.addType != 'artists' ? 3 : 4}> <Grid item xs={12} sm={this.state.addType != 'artists' ? 3 : 4} md={this.state.addType != 'artists' ? 3 : 4}>
@ -458,7 +505,7 @@ function ListBlock(props) {
alignItems="flex-start" alignItems="flex-start"
style={{padding: '24px'}}> style={{padding: '24px'}}>
{props.list.map((music_obj) => <BlockGridItem music_obj={ music_obj } key={ music_obj.name } {props.list.map((music_obj) => <BlockGridItem music_obj={ music_obj } key={ music_obj.name }
handler={ props.handler } addType={ props.addType } showTime={ props.showTime }/>)} deleteHandler={ props.deleteHandler } viewHandler={ props.viewHandler } addType={ props.addType } showTime={ props.showTime }/>)}
</Grid> </Grid>
} }
@ -504,9 +551,14 @@ function BlockGridItem (props) {
{/* DELETE BUTTON */} {/* DELETE BUTTON */}
<CardActions> <CardActions>
<Button className="full-width" color="secondary" variant="contained" aria-label="delete" onClick={(e) => props.handler(props.music_obj, props.addType, e)} startIcon={<Delete />}> <ButtonGroup className="full-width" orientation="vertical" color="secondary" variant="contained">
Delete <Button className="full-width" aria-label="goto" onClick={(e) => props.viewHandler(props.music_obj, props.addType, e)} startIcon={<ExitToApp />}>
</Button> View
</Button>
<Button className="full-width" aria-label="delete" onClick={(e) => props.deleteHandler(props.music_obj, props.addType, e)} startIcon={<Delete />}>
Delete
</Button>
</ButtonGroup>
</CardActions> </CardActions>
</Card> </Card>
</Grid> </Grid>