initial commit with first pass backend
This commit is contained in:
commit
549d8b4e10
121
.gitignore
vendored
Normal file
121
.gitignore
vendored
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
*/__pycache__/*
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
.idea
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
pip-wheel-metadata/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# celery beat schedule file
|
||||||
|
celerybeat-schedule
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
11
app.yaml
Normal file
11
app.yaml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
runtime: python37
|
||||||
|
service: spotify
|
||||||
|
|
||||||
|
handlers:
|
||||||
|
- url: /static
|
||||||
|
static_dir: build
|
||||||
|
|
||||||
|
- url: /.*
|
||||||
|
script: auto
|
||||||
|
secure: always
|
||||||
|
|
6
main.py
Normal file
6
main.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
from spotify import app
|
||||||
|
|
||||||
|
app = app
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app.run(host='127.0.0.1', port=8080, debug=True)
|
1
spotify/__init__.py
Normal file
1
spotify/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
from .spotify import app
|
38
spotify/spotify.py
Normal file
38
spotify/spotify.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
from flask import Flask, render_template, redirect
|
||||||
|
from google.cloud import firestore
|
||||||
|
import os
|
||||||
|
import urllib
|
||||||
|
|
||||||
|
# Project ID is determined by the GCLOUD_PROJECT environment variable
|
||||||
|
db = firestore.Client()
|
||||||
|
|
||||||
|
app = Flask(__name__, static_folder=os.path.join(os.path.dirname(__file__), '..', 'build'), template_folder="templates")
|
||||||
|
|
||||||
|
staticbucketurl = 'https://storage.googleapis.com/sarsooxyzstatic/'
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/')
|
||||||
|
def main():
|
||||||
|
return render_template('index.html')
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/auth')
|
||||||
|
def auth():
|
||||||
|
client_id = db.document('key/spotify').get().to_dict()['clientid']
|
||||||
|
params = urllib.parse.urlencode(
|
||||||
|
{
|
||||||
|
'client_id': client_id,
|
||||||
|
'response_type': 'code',
|
||||||
|
'scope': 'playlist-modify-public playlist-modify-private playlist-read-private',
|
||||||
|
'redirect_uri': 'https://spotify.sarsoo.xyz/app'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return redirect(urllib.parse.urlunparse(['https', 'accounts.spotify.com', 'authorize', '', params, '']))
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/app')
|
||||||
|
def app_route():
|
||||||
|
return render_template('app.html')
|
||||||
|
|
||||||
|
# [END gae_python37_app]
|
8
spotify/templates/app.html
Normal file
8
spotify/templates/app.html
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block title %}spotify{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="row"></div>
|
||||||
|
{% endblock %}
|
33
spotify/templates/base.html
Normal file
33
spotify/templates/base.html
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>sarsoo/{% block title %}{% endblock %}</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Pirata+One|Lato" rel="stylesheet">
|
||||||
|
|
||||||
|
<link rel="apple-touch-icon" sizes="180x180" href="https://storage.googleapis.com/sarsooxyzstatic/apple-touch-icon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="32x32" href="https://storage.googleapis.com/sarsooxyzstatic/favicon-32x32.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="16x16" href="https://storage.googleapis.com/sarsooxyzstatic/favicon-16x16.png">
|
||||||
|
<link rel="manifest" href="https://storage.googleapis.com/sarsooxyzstatic/site.webmanifest">
|
||||||
|
<link rel="mask-icon" href="https://storage.googleapis.com/sarsooxyzstatic/safari-pinned-tab.svg" color="#5bbad5">
|
||||||
|
<link rel="shortcut icon" href="https://storage.googleapis.com/sarsooxyzstatic/favicon.ico">
|
||||||
|
|
||||||
|
{% block scripts %}{% endblock %}
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
<h1 class="title">andy</h1>
|
||||||
|
</div>
|
||||||
|
<br><br>
|
||||||
|
<ul class="navbar">
|
||||||
|
<li><a href="/">home</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
<footer>
|
||||||
|
<a href="https://github.com/Sarsoo/sarsoo.xyz">view source code</a>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
16
spotify/templates/index.html
Normal file
16
spotify/templates/index.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block title %}spotify{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="pad-12 card">
|
||||||
|
<h1>Spotify Playlist Manager</h1>
|
||||||
|
|
||||||
|
<p class="center-text">create "super-playlists" of smaller modular playlists</p>
|
||||||
|
|
||||||
|
<a class="button full-width" href="/auth">launch</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
257
src/scss/style.scss
Normal file
257
src/scss/style.scss
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
$font-stack: 'Lato', arial;
|
||||||
|
$background-colour: #202124;
|
||||||
|
$ui-colour: #131313;
|
||||||
|
$text-colour: white;
|
||||||
|
|
||||||
|
$pad-px: 20px;
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
font-family: $font-stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: $background-colour;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: $text-colour;
|
||||||
|
font-size: 20px;
|
||||||
|
/*text-shadow: 1px 1px 1px #aaa;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: $text-colour;
|
||||||
|
font-size: 20px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center-text {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.full-width {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
background-color: #505050;
|
||||||
|
color: black;
|
||||||
|
border-radius: 10px;
|
||||||
|
display: inline-block;
|
||||||
|
margin: 4px auto;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 15px;
|
||||||
|
box-shadow: 2px 2px 4px black;
|
||||||
|
/*-webkit-transition-duration: 0.4s;
|
||||||
|
transition-duration: 0.4s;*/
|
||||||
|
|
||||||
|
text: {
|
||||||
|
align: center;
|
||||||
|
decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: 0 12px 16px 0 rgba(0,0,0,0.24),0 17px 50px 0 rgba(0,0,0,0.19);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
margin: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallerystrip{
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
margin: auto;
|
||||||
|
margin-top: 15px;
|
||||||
|
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: auto;
|
||||||
|
border: 10px solid #313439;
|
||||||
|
margin: $pad-px / 2;
|
||||||
|
box-shadow: 4px 4px 7px #070707;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile {
|
||||||
|
background-color: $ui-colour;
|
||||||
|
height: auto;
|
||||||
|
margin-top: 10px;
|
||||||
|
/*border: 8px solid #313439;*/
|
||||||
|
border-radius: 0px;
|
||||||
|
box-shadow: 7px 7px 8px black;
|
||||||
|
|
||||||
|
|
||||||
|
img {
|
||||||
|
border-radius: 50%;
|
||||||
|
display: block;
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
border: 8px solid #212121;
|
||||||
|
box-shadow: 4px 4px 3px #0c0c0c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h1.title {
|
||||||
|
color: black;
|
||||||
|
font-size: 6em;
|
||||||
|
font-family: 'Pirata One', arial;
|
||||||
|
text-shadow: 3px 3px 3px #aaa;
|
||||||
|
|
||||||
|
font-weight: bold;
|
||||||
|
display: block;
|
||||||
|
text-decoration: none;
|
||||||
|
background-color: white;
|
||||||
|
padding: 0px;
|
||||||
|
/*font-size: 16em;*/
|
||||||
|
width: 2.5em;
|
||||||
|
height: 1.3em;
|
||||||
|
text-align: center;
|
||||||
|
margin: auto;
|
||||||
|
box-shadow: 5px 5px 8px #000000;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
/*background-color: grey;*/
|
||||||
|
background-color: $ui-colour;
|
||||||
|
box-shadow: 4px 4px 8px black;
|
||||||
|
padding: 10px;
|
||||||
|
margin: $pad-px / 2;
|
||||||
|
/*border-radius: 3px;*/
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
text-align: center;
|
||||||
|
color: white;
|
||||||
|
text-shadow: 1px 1px 2px #4f4f4f;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 3px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
box-shadow: 2px 2px 2px black;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h1.sectiontitle {
|
||||||
|
text-align:center;
|
||||||
|
color: white;
|
||||||
|
font-family: 'Megrim', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.navbar {
|
||||||
|
list-style-type: none;
|
||||||
|
border-radius: 5px 5px;
|
||||||
|
/*box-shadow: 3px 3px 1px grey;*/
|
||||||
|
margin: 10px;
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: $ui-colour;
|
||||||
|
|
||||||
|
|
||||||
|
li {
|
||||||
|
float: left;
|
||||||
|
position: -webkit-sticky;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
|
||||||
|
|
||||||
|
a {
|
||||||
|
display: block;
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
padding: 14px 16px;
|
||||||
|
text-decoration: none;
|
||||||
|
text-shadow: 1px 1px 2px black;
|
||||||
|
-webkit-transition: background-color 0.4s;
|
||||||
|
transition: background-color 0.4s;
|
||||||
|
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #080808;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
li.right {float: right;}
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
p {
|
||||||
|
text-align: right;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
text-align: right;
|
||||||
|
display: block;
|
||||||
|
color: grey;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 600px) {
|
||||||
|
ul.navbar li.right,
|
||||||
|
ul.navbar li {float: none;}
|
||||||
|
}
|
||||||
|
|
||||||
|
[class*="col-"] {
|
||||||
|
float: left;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
[class*="pad-"] {
|
||||||
|
float: left;
|
||||||
|
width: calc(100% - #{$pad-px});
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (min-width: 768px) {
|
||||||
|
/* For desktop: */
|
||||||
|
.col-1 {width: 8.33%;}
|
||||||
|
.col-2 {width: 16.66%;}
|
||||||
|
.col-3 {width: 25%;}
|
||||||
|
.col-4 {width: 33.33%;}
|
||||||
|
.col-5 {width: 41.66%;}
|
||||||
|
.col-6 {width: 50%;}
|
||||||
|
.col-7 {width: 58.33%;}
|
||||||
|
.col-8 {width: 66.66%;}
|
||||||
|
.col-9 {width: 75%;}
|
||||||
|
.col-10 {width: 83.33%;}
|
||||||
|
.col-11 {width: 91.66%;}
|
||||||
|
.col-12 {width: 100%;}
|
||||||
|
|
||||||
|
/* For desktop: */
|
||||||
|
.pad-2 {width: calc(16.66% - #{$pad-px});}
|
||||||
|
.pad-3 {width: calc(25% - #{$pad-px});}
|
||||||
|
.pad-4 {width: calc(33.33% - #{$pad-px});}
|
||||||
|
.pad-5 {width: calc(41.66% - #{$pad-px});}
|
||||||
|
.pad-6 {width: calc(50% - #{$pad-px});}
|
||||||
|
.pad-7 {width: calc(58.33% - #{$pad-px});}
|
||||||
|
.pad-8 {width: calc(66.66% - #{$pad-px});}
|
||||||
|
.pad-9 {width: calc(75% - #{$pad-px});}
|
||||||
|
.pad-10 {width: calc(83.33% - #{$pad-px});}
|
||||||
|
.pad-11 {width: calc(91.66% - #{$pad-px});}
|
||||||
|
.pad-12 {width: calc(100% - #{$pad-px});}
|
||||||
|
}
|
||||||
|
|
||||||
|
.row::after {
|
||||||
|
content: "";
|
||||||
|
clear: both;
|
||||||
|
display: table;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user