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/.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/.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 c9753ec..171ed5c 100644 --- a/main.py +++ b/main.py @@ -1,41 +1,99 @@ import requests import os -from dotenv import load_dotenv -from flask import Flask, request, render_template +from flask import Flask, request, render_template, redirect, url_for from flask_bootstrap import Bootstrap5 - -from spotifySearch import searchSpotify - +from utils.spotifyAPI import searchSpotify +from utils.generateQRCode import generateQRCode +import sqlite3 +from random import randint app = Flask(__name__) bootstrap = Bootstrap5(app) -@app.route('/', methods=['GET', 'POST']) -def main_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, spotify_URL TEXT)") + +@app.route("/", methods=['GET', 'POST']) +def main(): + 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 is a great news, click the button below to access it.", type="success", roomid=roomid) + else: + 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=["GET", "POST"]) +def create_playlist(): + playlistName = request.form.get('roomName') + if not playlistName: + return redirect(url_for('main')) + + roomid = randint(10000000, 99999999) + while cursor.execute("SELECT * FROM rooms WHERE roomid = ?", (roomid,)).fetchone(): + roomid = randint(10000000, 99999999) + + 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) + 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("index.html") + return render_template("search.html", roomid=roomid, playlistName=playlistName, spotifyURL=spotifyURL) -@app.route('/add/', methods=['GET']) -def add_to_playlist(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") +@app.route('/add///', methods=['GET']) +def add_to_playlist(roomid, playlistID, trackid): + print(roomid) + print(playlistID) + print(trackid) + 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") + "/" + 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") + 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: - 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 + 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' + 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/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/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 index 438c683..5bd224f 100644 --- a/templates/found.html +++ b/templates/found.html @@ -8,6 +8,12 @@
+

Welcome

+

Choose the music that will play tonight.

+

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

+
+ +
@@ -35,7 +41,7 @@
{{ track[0] }}

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

- + diff --git a/templates/index.html b/templates/index.html index 602fde9..8f5ecf6 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..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/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/spotifySearch.py b/utils/spotifyAPI.py similarity index 88% rename from spotifySearch.py rename to utils/spotifyAPI.py index 7b3bb69..f78c79c 100644 --- a/spotifySearch.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() @@ -18,4 +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 + return tracks \ No newline at end of file