added js frontend skeleton with routing
This commit is contained in:
parent
549d8b4e10
commit
aaebf3a6e9
3
.babelrc
Normal file
3
.babelrc
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"presets": ["@babel/env", "@babel/preset-react"]
|
||||
}
|
22
.gcloudignore
Normal file
22
.gcloudignore
Normal file
@ -0,0 +1,22 @@
|
||||
# This file specifies files that are *not* uploaded to Google Cloud Platform
|
||||
# using gcloud. It follows the same syntax as .gitignore, with the addition of
|
||||
# "#!include" directives (which insert the entries of the given .gitignore-style
|
||||
# file at that point).
|
||||
#
|
||||
# For more information, run:
|
||||
# $ gcloud topic gcloudignore
|
||||
#
|
||||
.gcloudignore
|
||||
# If you would like to upload your .git directory, .gitignore file or files
|
||||
# from your .gitignore file, remove the corresponding line
|
||||
# below:
|
||||
.git
|
||||
.gitignore
|
||||
|
||||
venv
|
||||
node_modules
|
||||
|
||||
# Python pycache:
|
||||
__pycache__/
|
||||
# Ignored by the build system
|
||||
/setup.cfg
|
5835
package-lock.json
generated
Normal file
5835
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
39
package.json
Normal file
39
package.json
Normal file
@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "spotify.sarsoo.xyz",
|
||||
"version": "1.0.0",
|
||||
"description": "spotify playlist manager web app",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"build": "webpack --config webpack.prod.js",
|
||||
"devbuild": "webpack --config webpack.dev.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/Sarsoo/spotify-web.git"
|
||||
},
|
||||
"author": "sarsoo",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/Sarsoo/spotify-web/issues"
|
||||
},
|
||||
"homepage": "https://github.com/Sarsoo/spotify-web#readme",
|
||||
"dependencies": {
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6",
|
||||
"react-router-dom": "^5.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.5.5",
|
||||
"@babel/core": "^7.5.5",
|
||||
"@babel/preset-env": "^7.5.5",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"babel-loader": "^8.0.6",
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
"css-loader": "^3.1.0",
|
||||
"style-loader": "^0.23.1",
|
||||
"webpack": "^4.38.0",
|
||||
"webpack-cli": "^3.3.6",
|
||||
"webpack-merge": "^4.2.1"
|
||||
}
|
||||
}
|
24
requirements.txt
Normal file
24
requirements.txt
Normal file
@ -0,0 +1,24 @@
|
||||
cachetools==3.1.1
|
||||
certifi==2019.6.16
|
||||
chardet==3.0.4
|
||||
Click==7.0
|
||||
Flask==1.1.1
|
||||
google-api-core==1.14.0
|
||||
google-auth==1.6.3
|
||||
google-cloud-core==1.0.2
|
||||
google-cloud-firestore==1.3.0
|
||||
googleapis-common-protos==1.6.0
|
||||
grpcio==1.22.0
|
||||
idna==2.8
|
||||
itsdangerous==1.1.0
|
||||
Jinja2==2.10.1
|
||||
MarkupSafe==1.1.1
|
||||
protobuf==3.9.0
|
||||
pyasn1==0.4.5
|
||||
pyasn1-modules==0.2.5
|
||||
pytz==2019.1
|
||||
requests==2.22.0
|
||||
rsa==4.0
|
||||
six==1.12.0
|
||||
urllib3==1.25.3
|
||||
Werkzeug==0.15.5
|
@ -1,5 +1,9 @@
|
||||
from flask import Flask, render_template, redirect
|
||||
from flask import Flask, render_template, redirect, request
|
||||
from google.cloud import firestore
|
||||
import requests
|
||||
|
||||
from base64 import b64encode
|
||||
|
||||
import os
|
||||
import urllib
|
||||
|
||||
@ -24,15 +28,43 @@ def auth():
|
||||
'client_id': client_id,
|
||||
'response_type': 'code',
|
||||
'scope': 'playlist-modify-public playlist-modify-private playlist-read-private',
|
||||
'redirect_uri': 'https://spotify.sarsoo.xyz/app'
|
||||
'redirect_uri': 'https://spotify.sarsoo.xyz/token'
|
||||
}
|
||||
)
|
||||
|
||||
return redirect(urllib.parse.urlunparse(['https', 'accounts.spotify.com', 'authorize', '', params, '']))
|
||||
|
||||
|
||||
@app.route('/token')
|
||||
def token():
|
||||
|
||||
code = request.args.get('code', None)
|
||||
if code is None:
|
||||
error = request.args.get('error', None)
|
||||
else:
|
||||
app_credentials = db.document('key/spotify').get().to_dict()
|
||||
|
||||
idsecret = b64encode(bytes(app_credentials['clientid'] + ':' + app_credentials['clientsecret'], "utf-8")).decode("ascii")
|
||||
headers = {'Authorization': 'Basic %s' % idsecret}
|
||||
|
||||
data = {
|
||||
'grant_type': 'authorization_code',
|
||||
'code': code,
|
||||
'redirect_uri': 'https://spotify.sarsoo.xyz/token'
|
||||
}
|
||||
|
||||
req = requests.post('https://accounts.spotify.com/api/token', data=data, headers=headers)
|
||||
|
||||
if 200 <= req.status_code < 300:
|
||||
resp = req.json()
|
||||
print(resp)
|
||||
|
||||
return redirect('/app')
|
||||
|
||||
|
||||
@app.route('/app')
|
||||
def app_route():
|
||||
@app.route('/app/<path>')
|
||||
def app_route(path = None):
|
||||
return render_template('app.html')
|
||||
|
||||
# [END gae_python37_app]
|
||||
|
@ -1,8 +1,31 @@
|
||||
{% extends 'base.html' %}
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>sarsoo/spotify</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">
|
||||
|
||||
{% block title %}spotify{% endblock %}
|
||||
<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 content %}
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<h1 class="title">andy</h1>
|
||||
</div>
|
||||
|
||||
<div class="row"></div>
|
||||
{% endblock %}
|
||||
<br><br>
|
||||
|
||||
<div id="react"></div>
|
||||
<script src="{{ url_for('static', filename='js/app.bundle.js') }}"></script>
|
||||
|
||||
<footer>
|
||||
<a href="https://github.com/Sarsoo/sarsoo.xyz">view source code</a>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
8
src/js/Index.js
Normal file
8
src/js/Index.js
Normal file
@ -0,0 +1,8 @@
|
||||
import React, { Component } from "react";
|
||||
|
||||
function Index(props){
|
||||
|
||||
return <p>index</p>;
|
||||
}
|
||||
|
||||
export default Index;
|
25
src/js/PlaylistManager.js
Normal file
25
src/js/PlaylistManager.js
Normal file
@ -0,0 +1,25 @@
|
||||
import React, { Component } from "react";
|
||||
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
|
||||
|
||||
import Index from "./Index.js";
|
||||
import Settings from "./Settings.js";
|
||||
|
||||
class PlaylistManager extends Component {
|
||||
|
||||
render(){
|
||||
return (
|
||||
<Router>
|
||||
<ul className="navbar">
|
||||
<li><Link to="/app">home</Link></li>
|
||||
<li><Link to="/app/settings">settings</Link></li>
|
||||
</ul>
|
||||
|
||||
<Route path="/app" exact component={Index} />
|
||||
<Route path="/app/settings" component={Settings} />
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default PlaylistManager;
|
8
src/js/Settings.js
Normal file
8
src/js/Settings.js
Normal file
@ -0,0 +1,8 @@
|
||||
import React, { Component } from "react";
|
||||
|
||||
function Settings(props){
|
||||
|
||||
return <p>settings</p>;
|
||||
}
|
||||
|
||||
export default Settings;
|
6
src/js/app.js
Normal file
6
src/js/app.js
Normal file
@ -0,0 +1,6 @@
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
import PlaylistManager from "./PlaylistManager.js";
|
||||
|
||||
ReactDOM.render(<PlaylistManager />, document.getElementById('react'));
|
31
webpack.common.js
Normal file
31
webpack.common.js
Normal file
@ -0,0 +1,31 @@
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
||||
|
||||
module.exports = {
|
||||
entry: {
|
||||
app: './src/js/app.js'
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(js|jsx)$/,
|
||||
exclude: /(node_modules|bower_components)/,
|
||||
loader: "babel-loader",
|
||||
options: { presets: ["@babel/env"] }
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: ["style-loader", "css-loader"]
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
new CleanWebpackPlugin()
|
||||
],
|
||||
resolve: { extensions: ["*", ".js", ".jsx"] },
|
||||
output: {
|
||||
filename: '[name].bundle.js',
|
||||
path: path.resolve(__dirname, 'build/js')
|
||||
}
|
||||
};
|
8
webpack.dev.js
Normal file
8
webpack.dev.js
Normal file
@ -0,0 +1,8 @@
|
||||
const merge = require('webpack-merge');
|
||||
const common = require('./webpack.common.js');
|
||||
|
||||
module.exports = merge(common, {
|
||||
mode: 'development',
|
||||
devtool: 'inline-source-map',
|
||||
watch: true
|
||||
});
|
7
webpack.prod.js
Normal file
7
webpack.prod.js
Normal file
@ -0,0 +1,7 @@
|
||||
const merge = require('webpack-merge');
|
||||
const common = require('./webpack.common.js');
|
||||
|
||||
module.exports = merge(common, {
|
||||
mode: 'production',
|
||||
devtool: 'source-map'
|
||||
});
|
Loading…
Reference in New Issue
Block a user