diff --git a/music/model/playlist.py b/music/model/playlist.py
index 45dcf99..88e2823 100644
--- a/music/model/playlist.py
+++ b/music/model/playlist.py
@@ -54,6 +54,8 @@ class Playlist(Model):
add_this_month = BooleanField(default=False)
day_boundary = NumberField(default=21)
+ include_spotify_owned = BooleanField(default=True)
+
chart_range = TextField(default='MONTH')
chart_limit = NumberField(default=50)
diff --git a/music/model/user.py b/music/model/user.py
index 84b1c65..1272727 100644
--- a/music/model/user.py
+++ b/music/model/user.py
@@ -89,3 +89,11 @@ class User(Model):
return matches[0]
else:
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()
diff --git a/music/tasks/run_user_playlist.py b/music/tasks/run_user_playlist.py
index 9b48e7a..8b3ed83 100644
--- a/music/tasks/run_user_playlist.py
+++ b/music/tasks/run_user_playlist.py
@@ -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})')
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:
logger.exception(f'error occured while retrieving playlists {username} / {playlist_name}')
raise e
diff --git a/src/js/Tag/View.js b/src/js/Tag/View.js
index bc6bc09..4ac4139 100644
--- a/src/js/Tag/View.js
+++ b/src/js/Tag/View.js
@@ -1,8 +1,8 @@
import React, { Component } from "react";
const axios = require('axios');
-import { Card, Button, CardActions, CardContent, FormControl, InputLabel, Select, Typography, Grid, TextField, MenuItem, FormControlLabel, Switch } from '@material-ui/core';
-import { Delete } from '@material-ui/icons';
+import { Card, Button, ButtonGroup, CardActions, CardContent, FormControl, InputLabel, Select, Typography, Grid, TextField, MenuItem, FormControlLabel, Switch } from '@material-ui/core';
+import { Delete, ExitToApp } from '@material-ui/icons';
import { makeStyles } from '@material-ui/core/styles';
import showMessage from "../Toast.js";
@@ -28,6 +28,7 @@ class TagView extends Component{
super(props);
this.state = {
tag_id: props.match.params.tag_id,
+ username: null,
tag: {
name: "",
tracks: [],
@@ -44,6 +45,7 @@ class TagView extends Component{
}
this.handleInputChange = this.handleInputChange.bind(this);
this.handleRun = this.handleRun.bind(this);
+ this.handleView = this.handleView.bind(this);
this.handleRemoveObj = this.handleRemoveObj.bind(this);
this.handleCheckChange = this.handleCheckChange.bind(this);
@@ -58,6 +60,7 @@ class TagView extends Component{
*/
componentDidMount(){
this.getTag();
+ this.getUserInfo();
// var intervalId = setInterval(() => {this.getTag(false)}, 5000);
// var timeoutId = setTimeout(() => {clearInterval(this.state.intervalId)}, 300000);
@@ -72,6 +75,26 @@ class TagView extends Component{
// 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
* @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
* @param {*} music_obj Subject object to remove
@@ -334,17 +381,17 @@ class TagView extends Component{
{/* ARTISTS TITLE */}
{ this.state.tag.artists.length > 0 && Artists }
{/* ARTIST CARDS */}
- { this.state.tag.artists.length > 0 && }
+ { this.state.tag.artists.length > 0 && }
{/* ALBUMS TITLE */}
{ this.state.tag.albums.length > 0 && Albums }
{/* ALBUM CARDS */}
- { this.state.tag.albums.length > 0 && }
+ { this.state.tag.albums.length > 0 && }
{/* TRACKS TITLE */}
{ this.state.tag.tracks.length > 0 && Tracks }
{/* TRACK CARDS */}
- { this.state.tag.tracks.length > 0 && }
+ { this.state.tag.tracks.length > 0 && }
{/* NAME TEXTBOX */}
@@ -458,7 +505,7 @@ function ListBlock(props) {
alignItems="flex-start"
style={{padding: '24px'}}>
{props.list.map((music_obj) => )}
+ deleteHandler={ props.deleteHandler } viewHandler={ props.viewHandler } addType={ props.addType } showTime={ props.showTime }/>)}
}
@@ -504,9 +551,14 @@ function BlockGridItem (props) {
{/* DELETE BUTTON */}
-
+
+
+
+