From 5907f5f7862f3abe641086ac5534687cf7476a25 Mon Sep 17 00:00:00 2001 From: Louis Gallet Date: Sun, 30 Jun 2024 22:55:01 +0200 Subject: [PATCH 1/7] feat: :construction: Starting working on roomID --- .gitignore | 2 ++ main.py | 32 ++++++++++++++++++++------------ templates/add.html | 2 +- templates/found.html | 2 +- 4 files changed, 24 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index 4a5762c..09b72b2 100644 --- a/.gitignore +++ b/.gitignore @@ -267,3 +267,5 @@ cython_debug/ # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ + +database.db diff --git a/main.py b/main.py index c9753ec..22381bd 100644 --- a/main.py +++ b/main.py @@ -3,39 +3,47 @@ import os from dotenv import load_dotenv from flask import Flask, request, render_template from flask_bootstrap import Bootstrap5 - from spotifySearch import searchSpotify +import sqlite3 + app = Flask(__name__) bootstrap = Bootstrap5(app) -@app.route('/', methods=['GET', 'POST']) -def main_app(): +database = sqlite3.connect("database.db") + +@app.route("/", methods=['GET']) +def main(): + return "Hello, World!" + +@app.route('/search/', methods=['GET', 'POST']) +def main_app(roomid): # handle the POST request if request.method == 'POST': search = request.form.get('search') result = searchSpotify(search) - return render_template("found.html", query=search, tracks=result) + return render_template("found.html", query=search, tracks=result, roomid=roomid) # otherwise handle the GET request return render_template("index.html") -@app.route('/add/', methods=['GET']) -def add_to_playlist(trackid): +@app.route('/add//', methods=['GET']) +def add_to_playlist(roomid, trackid): + print(roomid) + print(trackid) if not os.getenv("n8n_webhook"): - return render_template("add.html", response="No n8n webhook provided", comment="Please provide a n8n webhook in the .env file", type="error") + return render_template("add.html", response="No n8n webhook provided", comment="Please provide a n8n webhook in the .env file", type="error", roomid=roomid) try: - data = requests.get(os.getenv("n8n_webhook") + "/" + trackid) + data = requests.get(os.getenv("n8n_webhook") + "/" + roomid + "/" + trackid) if data.json()['message'] == 'Workflow was started': - return render_template("add.html", response="Track added to playlist successfully", comment="Enjoy the night \U0001f57a", type="success") + return render_template("add.html", response="Track added to playlist successfully", comment="Enjoy the night \U0001f57a", type="success", roomid=roomid) else: - return render_template("add.html", response='Invalid response from server', comment=data.text, type="error") + return render_template("add.html", response='Invalid response from server', comment=data.text, type="error", roomid=roomid) except requests.exceptions.RequestException as e: - return render_template("add.html", response='Request failed', comment=e, type="error") + return render_template("add.html", response='Request failed', comment=e, type="error", roomid=roomid) if __name__ == '__main__': - # run app in debug mode on port 5000 app.run(debug=True, port="3000", host="0.0.0.0") \ No newline at end of file diff --git a/templates/add.html b/templates/add.html index fd6bfa0..90abaf0 100644 --- a/templates/add.html +++ b/templates/add.html @@ -16,7 +16,7 @@ icon: "{{ type }}", confirmButtonText: "Add another track", }).then(function() { - window.location = "/"; + window.location = "/search/{{ roomid }}"; }) diff --git a/templates/found.html b/templates/found.html index 438c683..9105705 100644 --- a/templates/found.html +++ b/templates/found.html @@ -35,7 +35,7 @@
{{ track[0] }}

{{ track[1] }} - {{ track[2] }}

-
+
-- 2.47.2 From 788b81402b5d1a54f6b30f29a6ff81256ca61595 Mon Sep 17 00:00:00 2001 From: Louis Gallet Date: Sun, 30 Jun 2024 23:35:59 +0200 Subject: [PATCH 2/7] feat: :construction: Create base page for roomID selection --- .env.example | 3 +- .idea/dataSources.xml | 12 ++++ .idea/sqldialects.xml | 7 +++ main.py | 32 +++++++--- templates/index.html | 84 ++++++++++++++++++------- templates/search.html | 26 ++++++++ spotifySearch.py => utils/spotifyAPI.py | 5 ++ 7 files changed, 137 insertions(+), 32 deletions(-) create mode 100644 .idea/dataSources.xml create mode 100644 .idea/sqldialects.xml create mode 100644 templates/search.html rename spotifySearch.py => utils/spotifyAPI.py (92%) diff --git a/.env.example b/.env.example index cb8416c..ecf80a4 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,4 @@ client_id= client_secret= -n8n_webhook= \ No newline at end of file +n8n_webhook= +enviroment=dev \ No newline at end of file diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml new file mode 100644 index 0000000..4dd9ac1 --- /dev/null +++ b/.idea/dataSources.xml @@ -0,0 +1,12 @@ + + + + + sqlite.xerial + true + org.sqlite.JDBC + jdbc:sqlite:database.db + $ProjectFileDir$ + + + \ No newline at end of file diff --git a/.idea/sqldialects.xml b/.idea/sqldialects.xml new file mode 100644 index 0000000..9011cb5 --- /dev/null +++ b/.idea/sqldialects.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/main.py b/main.py index 22381bd..2a67d82 100644 --- a/main.py +++ b/main.py @@ -1,9 +1,8 @@ import requests import os -from dotenv import load_dotenv from flask import Flask, request, render_template from flask_bootstrap import Bootstrap5 -from spotifySearch import searchSpotify +from utils.spotifyAPI import searchSpotify import sqlite3 @@ -11,11 +10,24 @@ import sqlite3 app = Flask(__name__) bootstrap = Bootstrap5(app) -database = sqlite3.connect("database.db") +database = sqlite3.connect("database.db", check_same_thread=False) +cursor = database.cursor() +cursor.execute("CREATE TABLE IF NOT EXISTS rooms (roomid TEXT PRIMARY KEY, spotify_id TEXT)") -@app.route("/", methods=['GET']) +@app.route("/", methods=['GET', 'POST']) def main(): - return "Hello, World!" + if request.method == 'POST': + roomid = request.form.get('roomID') + if len(roomid) != 8: + return render_template("index.html", response="Invalid room id", comment="A room ID should be composed of number and have a lenght of 8 characters", type="error", roomid=roomid) + roomSearch = cursor.execute("SELECT * FROM rooms WHERE roomid = ?", (roomid,)).fetchone() + if roomSearch: + return render_template("index.html", response="We found your collaborative playlist", comment="It's great news, click the button below to access it.", type="success", roomid=roomid) + else: + cursor.execute("INSERT INTO rooms (roomid, spotify_id) VALUES (?, ?)", (roomid, "test")) + database.commit() + return render_template("index.html", response="We couldn't find your collaborative playlist", comment="Please check the room id and try again or create one.", type="error", roomid=roomid) + return render_template("index.html") @app.route('/search/', methods=['GET', 'POST']) def main_app(roomid): @@ -26,7 +38,7 @@ def main_app(roomid): return render_template("found.html", query=search, tracks=result, roomid=roomid) # otherwise handle the GET request - return render_template("index.html") + return render_template("search.html") @app.route('/add//', methods=['GET']) def add_to_playlist(roomid, trackid): @@ -46,4 +58,10 @@ def add_to_playlist(roomid, trackid): if __name__ == '__main__': - app.run(debug=True, port="3000", host="0.0.0.0") \ No newline at end of file + if not os.getenv("client_id") or not os.getenv("client_secret") or not os.getenv("n8n_webhook"): + print("Please provide client_id, client_secret and n8n_webhook in the .env file") + exit(1) + if os.getenv("enviroment") != "production": + app.run(debug=True, port="3000", host="0.0.0.0") + else: + app.run(debug=False, port="3000", host="0.0.0.0") \ No newline at end of file diff --git a/templates/index.html b/templates/index.html index 602fde9..2d4920e 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,28 +1,64 @@ - - - Fête de la musique - {{ bootstrap.load_css() }} - - -
-
-
-
- - + + + Fête de la musique + + {{ bootstrap.load_css() }} + + +
+

Make this playlist

+

You too, choose the music that will play tonight.

+
+
+

Join a room

+ +
+ + + If you don't have a room id, you can create one. +
+ + +
+
+

Create a room

+
+
+ + + This will be the playlist name +
+ +
+
-
- -
- -
- - - -
- +
+
+ +
+ \ No newline at end of file diff --git a/templates/search.html b/templates/search.html new file mode 100644 index 0000000..2777ac7 --- /dev/null +++ b/templates/search.html @@ -0,0 +1,26 @@ + + + + + Fête de la musique + {{ bootstrap.load_css() }} + + +
+
+
+
+ + +
+
+ +
+ +
+
+
+ + \ No newline at end of file diff --git a/spotifySearch.py b/utils/spotifyAPI.py similarity index 92% rename from spotifySearch.py rename to utils/spotifyAPI.py index 7b3bb69..a9c514b 100644 --- a/spotifySearch.py +++ b/utils/spotifyAPI.py @@ -19,3 +19,8 @@ def searchSpotify(spotifySearch, limit=10): trackID = results['tracks']['items'][i]['uri'] tracks.append([trackName, trackArtist, trackAlbum, trackPreview, trackImage, trackID]) return tracks + + +def createPlaylist(playlistName): + #TODO: Implement this function + pass \ No newline at end of file -- 2.47.2 From f3d606ee7d1f3cf20f24fde82be9e16be52e5d56 Mon Sep 17 00:00:00 2001 From: Louis Gallet Date: Sun, 30 Jun 2024 23:55:59 +0200 Subject: [PATCH 3/7] feat: :sparkles: Possiblity to join a room --- main.py | 15 +++++++++------ templates/found.html | 3 +++ templates/index.html | 2 +- templates/search.html | 5 ++++- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/main.py b/main.py index 2a67d82..a7e0173 100644 --- a/main.py +++ b/main.py @@ -12,7 +12,7 @@ bootstrap = Bootstrap5(app) database = sqlite3.connect("database.db", check_same_thread=False) cursor = database.cursor() -cursor.execute("CREATE TABLE IF NOT EXISTS rooms (roomid TEXT PRIMARY KEY, spotify_id TEXT)") +cursor.execute("CREATE TABLE IF NOT EXISTS rooms (roomid TEXT PRIMARY KEY, spotify_id TEXT, playlist_name TEXT)") @app.route("/", methods=['GET', 'POST']) def main(): @@ -22,23 +22,26 @@ def main(): return render_template("index.html", response="Invalid room id", comment="A room ID should be composed of number and have a lenght of 8 characters", type="error", roomid=roomid) roomSearch = cursor.execute("SELECT * FROM rooms WHERE roomid = ?", (roomid,)).fetchone() if roomSearch: - return render_template("index.html", response="We found your collaborative playlist", comment="It's great news, click the button below to access it.", type="success", roomid=roomid) + return render_template("index.html", response="We found your collaborative playlist", comment="It is a great news, click the button below to access it.", type="success", roomid=roomid) else: - cursor.execute("INSERT INTO rooms (roomid, spotify_id) VALUES (?, ?)", (roomid, "test")) + cursor.execute("INSERT INTO rooms (roomid, spotify_id, playlist_name) VALUES (?, ?, ?)", (roomid, "test", "test")) database.commit() - return render_template("index.html", response="We couldn't find your collaborative playlist", comment="Please check the room id and try again or create one.", type="error", roomid=roomid) + return render_template("index.html", response="We could not find your collaborative playlist", comment="Please check the room id and try again or create one.", type="error", roomid=roomid) return render_template("index.html") @app.route('/search/', methods=['GET', 'POST']) def main_app(roomid): + if len(roomid) != 8 or not cursor.execute("SELECT * FROM rooms WHERE roomid = ?", (roomid,)).fetchone(): + return main() + playlistName = cursor.execute("SELECT playlist_name FROM rooms WHERE roomid = ?", (roomid,)).fetchone()[0] # handle the POST request if request.method == 'POST': search = request.form.get('search') result = searchSpotify(search) - return render_template("found.html", query=search, tracks=result, roomid=roomid) + return render_template("found.html", query=search, tracks=result, roomid=roomid, playlistName=playlistName) # otherwise handle the GET request - return render_template("search.html") + return render_template("search.html", roomid=roomid, playlistName=playlistName) @app.route('/add//', methods=['GET']) def add_to_playlist(roomid, trackid): diff --git a/templates/found.html b/templates/found.html index 9105705..4abb2f2 100644 --- a/templates/found.html +++ b/templates/found.html @@ -8,6 +8,9 @@
+

Welcome

+

Choose the music that will play tonight.

+

Info: You're in room: {{ roomid }} , the playlist is called: {{ playlistName }}

diff --git a/templates/index.html b/templates/index.html index 2d4920e..8f5ecf6 100644 --- a/templates/index.html +++ b/templates/index.html @@ -43,7 +43,7 @@ title: "{{ response }}", text: "{{ comment }}", icon: "{{ type }}", - confirmButtonText: "Join another room", + confirmButtonText: "Let's get in!", }).then(function() { window.location = "/search/{{ roomid }}"; }) diff --git a/templates/search.html b/templates/search.html index 2777ac7..e702982 100644 --- a/templates/search.html +++ b/templates/search.html @@ -6,7 +6,10 @@ {{ bootstrap.load_css() }} -
+
+

Welcome

+

Choose the music that will play tonight.

+

Info: You're in room: {{ roomid }} , the playlist is called: {{ playlistName }}

-- 2.47.2 From 708c8beac65a613f9a586b072077a84e6551e7a7 Mon Sep 17 00:00:00 2001 From: Louis Gallet Date: Mon, 1 Jul 2024 00:19:39 +0200 Subject: [PATCH 4/7] feat: :construction: Starting working on Spotify authentification for playlist creation --- main.py | 18 +++++++++++++++--- templates/create.html | 34 ++++++++++++++++++++++++++++++++++ utils/spotifyAPI.py | 11 ++++++++++- 3 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 templates/create.html diff --git a/main.py b/main.py index a7e0173..aee6936 100644 --- a/main.py +++ b/main.py @@ -3,8 +3,8 @@ import os from flask import Flask, request, render_template from flask_bootstrap import Bootstrap5 from utils.spotifyAPI import searchSpotify - import sqlite3 +from random import randint app = Flask(__name__) @@ -24,11 +24,23 @@ def main(): if roomSearch: return render_template("index.html", response="We found your collaborative playlist", comment="It is a great news, click the button below to access it.", type="success", roomid=roomid) else: - cursor.execute("INSERT INTO rooms (roomid, spotify_id, playlist_name) VALUES (?, ?, ?)", (roomid, "test", "test")) - database.commit() return render_template("index.html", response="We could not find your collaborative playlist", comment="Please check the room id and try again or create one.", type="error", roomid=roomid) return render_template("index.html") +@app.route('/create', methods=["POST"]) +def create_playlist(): + playlistName = request.form.get('roomName') + if not playlistName: + return render_template("create.html", response="Invalid playlist name", comment="Please provide a valid playlist name", type="error") + playlistID = "test" + # check if the room id already exists + roomid = randint(10000000, 99999999) + while cursor.execute("SELECT * FROM rooms WHERE roomid = ?", (roomid,)).fetchone(): + roomid = randint(10000000, 99999999) + cursor.execute("INSERT INTO rooms (roomid, spotify_id, playlist_name) VALUES (?, ?, ?)", (roomid, playlistID, playlistName)) + database.commit() + return render_template("create.html", response="Playlist created successfully", comment="Enjoy the night \U0001f57a", type="success", roomid=roomid) + @app.route('/search/', methods=['GET', 'POST']) def main_app(roomid): if len(roomid) != 8 or not cursor.execute("SELECT * FROM rooms WHERE roomid = ?", (roomid,)).fetchone(): diff --git a/templates/create.html b/templates/create.html new file mode 100644 index 0000000..9f9d553 --- /dev/null +++ b/templates/create.html @@ -0,0 +1,34 @@ + + + + + Fête de la musique + + {{ bootstrap.load_css() }} + + +
+
+ +
+
+ \ No newline at end of file diff --git a/utils/spotifyAPI.py b/utils/spotifyAPI.py index a9c514b..3161b24 100644 --- a/utils/spotifyAPI.py +++ b/utils/spotifyAPI.py @@ -23,4 +23,13 @@ def searchSpotify(spotifySearch, limit=10): def createPlaylist(playlistName): #TODO: Implement this function - pass \ No newline at end of file + pass + +def spotifyLogin(): + """ + This function is used to login to spotify to get the user token + :return: user token + """ + credentials = spotipy.oauth2.SpotifyClientCredentials(client_id=os.getenv("client_id"), client_secret=os.getenv("client_secret")) + spotify_token = credentials.get_access_token() + return spotify_token \ No newline at end of file -- 2.47.2 From 9a1e02c90a54426c0d634b781393ce651a627094 Mon Sep 17 00:00:00 2001 From: Louis Gallet Date: Mon, 1 Jul 2024 00:42:46 +0200 Subject: [PATCH 5/7] feat: :construction: Starting working on spotify auth + create QR code for easy sharing --- main.py | 26 +++++++++++++++++++++----- templates/create.html | 1 + utils/generateQRCode.py | 18 ++++++++++++++++++ utils/spotifyAPI.py | 18 +++++++++++------- 4 files changed, 51 insertions(+), 12 deletions(-) create mode 100644 utils/generateQRCode.py diff --git a/main.py b/main.py index aee6936..76b196e 100644 --- a/main.py +++ b/main.py @@ -1,12 +1,12 @@ import requests import os -from flask import Flask, request, render_template +from flask import Flask, request, render_template, redirect, session, url_for from flask_bootstrap import Bootstrap5 -from utils.spotifyAPI import searchSpotify +from utils.spotifyAPI import searchSpotify, create_spotify_oauth +from utils.generateQRCode import generateQRCode import sqlite3 from random import randint - app = Flask(__name__) bootstrap = Bootstrap5(app) @@ -31,7 +31,7 @@ def main(): def create_playlist(): playlistName = request.form.get('roomName') if not playlistName: - return render_template("create.html", response="Invalid playlist name", comment="Please provide a valid playlist name", type="error") + return redirect(url_for('main')) playlistID = "test" # check if the room id already exists roomid = randint(10000000, 99999999) @@ -39,7 +39,9 @@ def create_playlist(): roomid = randint(10000000, 99999999) cursor.execute("INSERT INTO rooms (roomid, spotify_id, playlist_name) VALUES (?, ?, ?)", (roomid, playlistID, playlistName)) database.commit() - return render_template("create.html", response="Playlist created successfully", comment="Enjoy the night \U0001f57a", type="success", roomid=roomid) + qrcode = generateQRCode("http://localhost:3000/search/" + str(roomid)) + print(qrcode) + return render_template("create.html", response="Playlist created successfully", comment="Enjoy the night \U0001f57a (and share this QRCode with your friends)", image=qrcode, type="success", roomid=roomid) @app.route('/search/', methods=['GET', 'POST']) def main_app(roomid): @@ -72,6 +74,20 @@ def add_to_playlist(roomid, trackid): return render_template("add.html", response='Request failed', comment=e, type="error", roomid=roomid) +@app.route('/authenticate') +def authentification(): + sp_auth = create_spotify_oauth() + auth_url = sp_auth.get_authorize_url() + return redirect(auth_url) + +@app.route('/callback') +def callback(): + sp_oauth = create_spotify_oauth() + code = requests.args.get('code') + token_info = sp_oauth.get_access_token(code) + session["TOKEN_INFO"] = token_info + return redirect(url_for('create')) + if __name__ == '__main__': if not os.getenv("client_id") or not os.getenv("client_secret") or not os.getenv("n8n_webhook"): print("Please provide client_id, client_secret and n8n_webhook in the .env file") diff --git a/templates/create.html b/templates/create.html index 9f9d553..ab6e6a2 100644 --- a/templates/create.html +++ b/templates/create.html @@ -24,6 +24,7 @@ title:"{{ response }}", text: "{{ comment }}", icon: "{{ type }}", + imageUrl: "data:image/png;base64, {{ image }}", confirmButtonText: "Add some music!", }).then(function() { window.location = "/search/{{ roomid }}"; diff --git a/utils/generateQRCode.py b/utils/generateQRCode.py new file mode 100644 index 0000000..4191572 --- /dev/null +++ b/utils/generateQRCode.py @@ -0,0 +1,18 @@ +import qrcode +from io import BytesIO +import base64 +def generateQRCode(url: str, img_name: str = 'QR_Code.png') -> str: + """ + This function generates a QR code from a given URL and saves it as an image file + :param url: URL to generate QR code from + :param img_name: Name of the image file + :return: base64 encoded image + """ + code = qrcode.QRCode(version=1, box_size=10, border=4) + code.add_data(url) + code.make(fit=True) + img = code.make_image(fill_color="black", back_color="white") + buffered = BytesIO() + img.save(buffered) + img_str = base64.b64encode(buffered.getvalue()).decode() + return img_str \ No newline at end of file diff --git a/utils/spotifyAPI.py b/utils/spotifyAPI.py index 3161b24..eba4f7c 100644 --- a/utils/spotifyAPI.py +++ b/utils/spotifyAPI.py @@ -1,7 +1,8 @@ import spotipy -from spotipy.oauth2 import SpotifyClientCredentials +from spotipy.oauth2 import SpotifyClientCredentials, SpotifyOAuth import os from dotenv import load_dotenv +from flask import url_for load_dotenv() @@ -25,11 +26,14 @@ def createPlaylist(playlistName): #TODO: Implement this function pass -def spotifyLogin(): +def create_spotify_oauth(): """ - This function is used to login to spotify to get the user token - :return: user token + This function creates a Spotify OAuth object + :return: SpotifyOAuth object """ - credentials = spotipy.oauth2.SpotifyClientCredentials(client_id=os.getenv("client_id"), client_secret=os.getenv("client_secret")) - spotify_token = credentials.get_access_token() - return spotify_token \ No newline at end of file + return SpotifyOAuth( + client_id=os.getenv("client_id"), + client_secret=os.getenv("client_secret"), + redirect_uri=url_for('callback', _external=True), + scope='playlist-modify-public' + ) \ No newline at end of file -- 2.47.2 From 8b8579e988a14f4d32022ef1fc4dd14f176af213 Mon Sep 17 00:00:00 2001 From: Louis Gallet Date: Mon, 1 Jul 2024 01:01:35 +0200 Subject: [PATCH 6/7] feat: :construction: Continue working on spotify integration --- main.py | 17 ++++++++---- templates/add.html | 26 ------------------ templates/create.html | 35 ----------------------- templates/found.html | 53 ----------------------------------- templates/index.html | 64 ------------------------------------------- templates/search.html | 29 -------------------- utils/spotifyAPI.py | 5 +++- 7 files changed, 16 insertions(+), 213 deletions(-) delete mode 100644 templates/add.html delete mode 100644 templates/create.html delete mode 100644 templates/found.html delete mode 100644 templates/index.html delete mode 100644 templates/search.html diff --git a/main.py b/main.py index 76b196e..b65e6d6 100644 --- a/main.py +++ b/main.py @@ -1,8 +1,9 @@ import requests import os -from flask import Flask, request, render_template, redirect, session, url_for +from flask import Flask, request, render_template, redirect, session, url_for, sessions +from flask_session import Session from flask_bootstrap import Bootstrap5 -from utils.spotifyAPI import searchSpotify, create_spotify_oauth +from utils.spotifyAPI import searchSpotify, create_spotify_oauth, get_spotify_username from utils.generateQRCode import generateQRCode import sqlite3 from random import randint @@ -27,7 +28,7 @@ def main(): return render_template("index.html", response="We could not find your collaborative playlist", comment="Please check the room id and try again or create one.", type="error", roomid=roomid) return render_template("index.html") -@app.route('/create', methods=["POST"]) +@app.route('/create', methods=["GET", "POST"]) def create_playlist(): playlistName = request.form.get('roomName') if not playlistName: @@ -78,20 +79,26 @@ def add_to_playlist(roomid, trackid): def authentification(): sp_auth = create_spotify_oauth() auth_url = sp_auth.get_authorize_url() + session["token_info"] = sp_auth.get_cached_token() return redirect(auth_url) @app.route('/callback') def callback(): sp_oauth = create_spotify_oauth() - code = requests.args.get('code') + code = request.args.get('code') token_info = sp_oauth.get_access_token(code) session["TOKEN_INFO"] = token_info - return redirect(url_for('create')) + return redirect(url_for('info')) + +@app.route("/info") +def info(): + return get_spotify_username() if __name__ == '__main__': if not os.getenv("client_id") or not os.getenv("client_secret") or not os.getenv("n8n_webhook"): print("Please provide client_id, client_secret and n8n_webhook in the .env file") exit(1) + app.secret_key = 'super secret key' if os.getenv("enviroment") != "production": app.run(debug=True, port="3000", host="0.0.0.0") else: diff --git a/templates/add.html b/templates/add.html deleted file mode 100644 index 90abaf0..0000000 --- a/templates/add.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - Fête de la musique - - {{ bootstrap.load_css() }} - - -
-
- -
-
- - \ No newline at end of file diff --git a/templates/create.html b/templates/create.html deleted file mode 100644 index ab6e6a2..0000000 --- a/templates/create.html +++ /dev/null @@ -1,35 +0,0 @@ - - - - - Fête de la musique - - {{ bootstrap.load_css() }} - - -
-
- -
-
- \ No newline at end of file diff --git a/templates/found.html b/templates/found.html deleted file mode 100644 index 4abb2f2..0000000 --- a/templates/found.html +++ /dev/null @@ -1,53 +0,0 @@ - - - - - Results - {{ bootstrap.load_css() }} - - - -
-

Welcome

-

Choose the music that will play tonight.

-

Info: You're in room: {{ roomid }} , the playlist is called: {{ playlistName }}

- -
-
- - -
-
- -
- -
- - -
-
- {% for track in tracks %} -
-
- Card image cap -
-
{{ track[0] }}
-

{{ track[1] }} - {{ track[2] }}

- -
- - -
-
-
-
- {% endfor %} -
- -
- - \ No newline at end of file diff --git a/templates/index.html b/templates/index.html deleted file mode 100644 index 8f5ecf6..0000000 --- a/templates/index.html +++ /dev/null @@ -1,64 +0,0 @@ - - - - - Fête de la musique - - {{ bootstrap.load_css() }} - - -
-

Make this playlist

-

You too, choose the music that will play tonight.

-
-
-

Join a room

-
-
- - - If you don't have a room id, you can create one. -
- -
-
-
-

Create a room

-
-
- - - This will be the playlist name -
- -
-
-
-
-
- -
- - \ No newline at end of file diff --git a/templates/search.html b/templates/search.html deleted file mode 100644 index e702982..0000000 --- a/templates/search.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - - Fête de la musique - {{ bootstrap.load_css() }} - - -
-

Welcome

-

Choose the music that will play tonight.

-

Info: You're in room: {{ roomid }} , the playlist is called: {{ playlistName }}

-
-
-
- - -
-
- -
- -
-
-
- - \ No newline at end of file diff --git a/utils/spotifyAPI.py b/utils/spotifyAPI.py index eba4f7c..c43a3b0 100644 --- a/utils/spotifyAPI.py +++ b/utils/spotifyAPI.py @@ -36,4 +36,7 @@ def create_spotify_oauth(): client_secret=os.getenv("client_secret"), redirect_uri=url_for('callback', _external=True), scope='playlist-modify-public' - ) \ No newline at end of file + ) + +def get_spotify_username(): + return spotipy.Spotify(auth_manager=SpotifyOAuth(client_id=os.getenv("client_id"), client_secret=os.getenv("client_secret"), redirect_uri=url_for('callback', _external=True))).me() \ No newline at end of file -- 2.47.2 From 6e5e14137254332e1f798eaaf686531e2f58fa5e Mon Sep 17 00:00:00 2001 From: Louis Gallet Date: Mon, 1 Jul 2024 17:13:37 +0200 Subject: [PATCH 7/7] feat: :sparkles: RoomID is fully implemented --- main.py | 70 ++++++++++++++++++++----------------------- templates/add.html | 26 ++++++++++++++++ templates/create.html | 35 ++++++++++++++++++++++ templates/found.html | 56 ++++++++++++++++++++++++++++++++++ templates/index.html | 64 +++++++++++++++++++++++++++++++++++++++ templates/search.html | 32 ++++++++++++++++++++ utils/spotifyAPI.py | 22 +------------- 7 files changed, 246 insertions(+), 59 deletions(-) create mode 100644 templates/add.html create mode 100644 templates/create.html create mode 100644 templates/found.html create mode 100644 templates/index.html create mode 100644 templates/search.html diff --git a/main.py b/main.py index b65e6d6..171ed5c 100644 --- a/main.py +++ b/main.py @@ -1,9 +1,8 @@ import requests import os -from flask import Flask, request, render_template, redirect, session, url_for, sessions -from flask_session import Session +from flask import Flask, request, render_template, redirect, url_for from flask_bootstrap import Bootstrap5 -from utils.spotifyAPI import searchSpotify, create_spotify_oauth, get_spotify_username +from utils.spotifyAPI import searchSpotify from utils.generateQRCode import generateQRCode import sqlite3 from random import randint @@ -13,7 +12,7 @@ bootstrap = Bootstrap5(app) database = sqlite3.connect("database.db", check_same_thread=False) cursor = database.cursor() -cursor.execute("CREATE TABLE IF NOT EXISTS rooms (roomid TEXT PRIMARY KEY, spotify_id TEXT, playlist_name TEXT)") +cursor.execute("CREATE TABLE IF NOT EXISTS rooms (roomid TEXT PRIMARY KEY, spotify_id TEXT, playlist_name TEXT, spotify_URL TEXT)") @app.route("/", methods=['GET', 'POST']) def main(): @@ -33,40 +32,54 @@ def create_playlist(): playlistName = request.form.get('roomName') if not playlistName: return redirect(url_for('main')) - playlistID = "test" - # check if the room id already exists + roomid = randint(10000000, 99999999) while cursor.execute("SELECT * FROM rooms WHERE roomid = ?", (roomid,)).fetchone(): roomid = randint(10000000, 99999999) - cursor.execute("INSERT INTO rooms (roomid, spotify_id, playlist_name) VALUES (?, ?, ?)", (roomid, playlistID, playlistName)) - database.commit() - qrcode = generateQRCode("http://localhost:3000/search/" + str(roomid)) - print(qrcode) - return render_template("create.html", response="Playlist created successfully", comment="Enjoy the night \U0001f57a (and share this QRCode with your friends)", image=qrcode, type="success", roomid=roomid) + + try: + data = requests.get((os.getenv("n8n_webhook_create_playlist") + "/" + str(roomid) + "/" + playlistName)) + playlistID = data.json()['playlistID'] + spotifyURL = data.json()['spotifyURL'] + print(playlistID) + cursor.execute("INSERT INTO rooms (roomid, spotify_id, playlist_name, spotify_URL) VALUES (?, ?, ?, ?)", + (roomid, playlistID, playlistName, spotifyURL)) + database.commit() + qrcode = generateQRCode("http://localhost:3000/search/" + str(roomid)) + return render_template("create.html", response="Playlist created successfully", + comment="Enjoy the night \U0001f57a (and share this QRCode with your friends)", + image=qrcode, type="success", roomid=roomid) + + except requests.exceptions.RequestException as e: + return render_template("create.html", response='Request failed', comment=e, type="error") @app.route('/search/', methods=['GET', 'POST']) def main_app(roomid): if len(roomid) != 8 or not cursor.execute("SELECT * FROM rooms WHERE roomid = ?", (roomid,)).fetchone(): return main() playlistName = cursor.execute("SELECT playlist_name FROM rooms WHERE roomid = ?", (roomid,)).fetchone()[0] + playlistID = cursor.execute("SELECT spotify_id FROM rooms WHERE roomid = ?", (roomid,)).fetchone()[0] + spotifyURL = cursor.execute("SELECT spotify_URL FROM rooms WHERE roomid = ?", (roomid,)).fetchone()[0] # handle the POST request if request.method == 'POST': search = request.form.get('search') result = searchSpotify(search) - return render_template("found.html", query=search, tracks=result, roomid=roomid, playlistName=playlistName) + return render_template("found.html", query=search, tracks=result, roomid=roomid, playlistName=playlistName, playlistID=playlistID, spotifyURL=spotifyURL) # otherwise handle the GET request - return render_template("search.html", roomid=roomid, playlistName=playlistName) + return render_template("search.html", roomid=roomid, playlistName=playlistName, spotifyURL=spotifyURL) -@app.route('/add//', methods=['GET']) -def add_to_playlist(roomid, trackid): +@app.route('/add///', methods=['GET']) +def add_to_playlist(roomid, playlistID, trackid): print(roomid) + print(playlistID) print(trackid) - if not os.getenv("n8n_webhook"): + if not os.getenv("n8n_webhook_add_tracks"): return render_template("add.html", response="No n8n webhook provided", comment="Please provide a n8n webhook in the .env file", type="error", roomid=roomid) try: - data = requests.get(os.getenv("n8n_webhook") + "/" + roomid + "/" + trackid) - if data.json()['message'] == 'Workflow was started': + data = requests.get(os.getenv("n8n_webhook_add_tracks") + "/" + playlistID + "/" + trackid) + print(data.json) + if data.json()['status'] == 'success': return render_template("add.html", response="Track added to playlist successfully", comment="Enjoy the night \U0001f57a", type="success", roomid=roomid) else: @@ -75,27 +88,8 @@ def add_to_playlist(roomid, trackid): return render_template("add.html", response='Request failed', comment=e, type="error", roomid=roomid) -@app.route('/authenticate') -def authentification(): - sp_auth = create_spotify_oauth() - auth_url = sp_auth.get_authorize_url() - session["token_info"] = sp_auth.get_cached_token() - return redirect(auth_url) - -@app.route('/callback') -def callback(): - sp_oauth = create_spotify_oauth() - code = request.args.get('code') - token_info = sp_oauth.get_access_token(code) - session["TOKEN_INFO"] = token_info - return redirect(url_for('info')) - -@app.route("/info") -def info(): - return get_spotify_username() - if __name__ == '__main__': - if not os.getenv("client_id") or not os.getenv("client_secret") or not os.getenv("n8n_webhook"): + if not os.getenv("client_id") or not os.getenv("client_secret") or not os.getenv("n8n_webhook_add_tracks") or not os.getenv("n8n_webhook_create_playlist"): print("Please provide client_id, client_secret and n8n_webhook in the .env file") exit(1) app.secret_key = 'super secret key' diff --git a/templates/add.html b/templates/add.html new file mode 100644 index 0000000..90abaf0 --- /dev/null +++ b/templates/add.html @@ -0,0 +1,26 @@ + + + + + Fête de la musique + + {{ bootstrap.load_css() }} + + +
+
+ +
+
+ + \ No newline at end of file diff --git a/templates/create.html b/templates/create.html new file mode 100644 index 0000000..ab6e6a2 --- /dev/null +++ b/templates/create.html @@ -0,0 +1,35 @@ + + + + + Fête de la musique + + {{ bootstrap.load_css() }} + + +
+
+ +
+
+ \ No newline at end of file diff --git a/templates/found.html b/templates/found.html new file mode 100644 index 0000000..5bd224f --- /dev/null +++ b/templates/found.html @@ -0,0 +1,56 @@ + + + + + Results + {{ bootstrap.load_css() }} + + + +
+

Welcome

+

Choose the music that will play tonight.

+

Info: You're in room: {{ roomid }} , the playlist is called: {{ playlistName }}

+
+ +
+
+
+
+ + +
+
+ +
+ +
+
+ +
+
+ {% for track in tracks %} +
+
+ Card image cap +
+
{{ track[0] }}
+

{{ track[1] }} - {{ track[2] }}

+ +
+ + +
+
+
+
+ {% endfor %} +
+ +
+ + \ No newline at end of file diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..8f5ecf6 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,64 @@ + + + + + Fête de la musique + + {{ bootstrap.load_css() }} + + +
+

Make this playlist

+

You too, choose the music that will play tonight.

+
+
+

Join a room

+
+
+ + + If you don't have a room id, you can create one. +
+ +
+
+
+

Create a room

+
+
+ + + This will be the playlist name +
+ +
+
+
+
+
+ +
+ + \ No newline at end of file diff --git a/templates/search.html b/templates/search.html new file mode 100644 index 0000000..c9f8a33 --- /dev/null +++ b/templates/search.html @@ -0,0 +1,32 @@ + + + + + Fête de la musique + {{ bootstrap.load_css() }} + + +
+

Welcome

+

Choose the music that will play tonight.

+

Info: You're in room: {{ roomid }} , the playlist is called: {{ playlistName }}

+
+ +
+
+
+
+ + +
+
+ +
+ +
+
+
+ + \ No newline at end of file diff --git a/utils/spotifyAPI.py b/utils/spotifyAPI.py index c43a3b0..f78c79c 100644 --- a/utils/spotifyAPI.py +++ b/utils/spotifyAPI.py @@ -19,24 +19,4 @@ def searchSpotify(spotifySearch, limit=10): trackImage = results['tracks']['items'][i]['album']['images'][0]['url'] trackID = results['tracks']['items'][i]['uri'] tracks.append([trackName, trackArtist, trackAlbum, trackPreview, trackImage, trackID]) - return tracks - - -def createPlaylist(playlistName): - #TODO: Implement this function - pass - -def create_spotify_oauth(): - """ - This function creates a Spotify OAuth object - :return: SpotifyOAuth object - """ - return SpotifyOAuth( - client_id=os.getenv("client_id"), - client_secret=os.getenv("client_secret"), - redirect_uri=url_for('callback', _external=True), - scope='playlist-modify-public' - ) - -def get_spotify_username(): - return spotipy.Spotify(auth_manager=SpotifyOAuth(client_id=os.getenv("client_id"), client_secret=os.getenv("client_secret"), redirect_uri=url_for('callback', _external=True))).me() \ No newline at end of file + return tracks \ No newline at end of file -- 2.47.2