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
|
from google.cloud import firestore
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from base64 import b64encode
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import urllib
|
import urllib
|
||||||
|
|
||||||
@ -24,15 +28,43 @@ def auth():
|
|||||||
'client_id': client_id,
|
'client_id': client_id,
|
||||||
'response_type': 'code',
|
'response_type': 'code',
|
||||||
'scope': 'playlist-modify-public playlist-modify-private playlist-read-private',
|
'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, '']))
|
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')
|
@app.route('/app')
|
||||||
def app_route():
|
@app.route('/app/<path>')
|
||||||
|
def app_route(path = None):
|
||||||
return render_template('app.html')
|
return render_template('app.html')
|
||||||
|
|
||||||
# [END gae_python37_app]
|
# [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>
|
<br><br>
|
||||||
{% endblock %}
|
|
||||||
|
<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