Skip to content

Commit

Permalink
First commit
Browse files Browse the repository at this point in the history
  • Loading branch information
shashi-sah2003 committed Apr 1, 2024
0 parents commit 3a0cdd8
Show file tree
Hide file tree
Showing 6 changed files with 372 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
youtube_credentials.txt
spotify_credentials.txt
Spotify_automation.py
Mp3downloader.py
final.csv
.cache
backend.cpython-311.pyc

175 changes: 175 additions & 0 deletions backend.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
from fastapi import FastAPI, Request, Form
from fastapi.responses import HTMLResponse, JSONResponse, FileResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from pytube import YouTube
import csv
from googleapiclient.discovery import build
import os
import spotipy
from spotipy.oauth2 import SpotifyClientCredentials
from typing import List
import zipfile

app = FastAPI()

app.mount("/static", StaticFiles(directory="static"), name="static")
templates = Jinja2Templates(directory="templates")

# Load YouTube API key from file
with open("youtube_credentials.txt") as f:
API_KEY = f.read().strip()

#extracting client id and client secret code in a secure way
with open("spotify_credentials.txt") as f:
[SPOTIPY_CLIENT_ID, SPOTIFY_CLIENT_SECRET] = f.read().split("\n")
f.close()

#Connecting with Spotify API
auth_manager = SpotifyClientCredentials(client_id=SPOTIPY_CLIENT_ID, client_secret=SPOTIFY_CLIENT_SECRET)
sp = spotipy.Spotify(auth_manager=auth_manager)


def generate_playlist_csv(playlist_link, user_id):
playlist_dict = sp.playlist(playlist_link)

no_of_songs = playlist_dict["tracks"]["total"]

album_list = []
song_list = []
release_date_list = []
artists_list = []

tracks = playlist_dict["tracks"]
items = tracks["items"]
offset = 0
i = 0

while i < no_of_songs:
song = items[i-offset]["track"]["name"]
album = items[i-offset]["track"]["album"]["name"]
release_date = items[i-offset]["track"]["album"]["release_date"]
artists = [k["name"] for k in items[i-offset]["track"]["artists"]]
artists = ','.join(artists)
album_list.append(album)
song_list.append(song)
release_date_list.append(release_date)
artists_list.append(artists)

if (i+1)%100 == 0:
tracks = sp.next(tracks)
items = tracks["items"]
offset = i+1

i+=1

final_data = list(zip(song_list,artists_list,album_list,release_date_list))

#Creating CSV File
csv_file_name = f"{user_id}_final.csv"
csv_file_path = os.path.join("csv_file", csv_file_name)


with open(csv_file_path, 'w', newline='') as f:
writer = csv.writer(f)
writer.writerow(["Name", "Artists", "Album", "Release Date"])
writer.writerows(final_data)

return csv_file_path



# Searching for a song on Youtube using YouTube Data API
def search_youtube(song_name, artist):
youtube = build('youtube', 'v3', developerKey=API_KEY)
search_query = song_name + ' ' + artist + ' audio'
request = youtube.search().list(
q=search_query,
part='id',
type='video',
maxResults=1
)
response = request.execute()
if 'items' in response:
if len(response['items']) > 0:
video_id = response['items'][0]['id']['videoId']
video_url = 'https://www.youtube.com/watch?v=' + video_id
return video_url
print(f"No search results found for '{song_name}' by {artist}.")
return None

# Download MP3 from YouTube using pytube
def download_mp3(youtube_url, user_folder):
try:
yt = YouTube(youtube_url)
stream = yt.streams.filter(only_audio=True).first()
if stream:
print("Downloading MP3...")

os.makedirs(user_folder, exist_ok=True)
file_name = f"{yt.title}.mp4"
# song_path = os.path.join(user_folder, f"{yt.title}.mp4")
stream.download(output_path=user_folder)
print("Download complete.\n")
return file_name
else:
print("No audio stream available for this video.")
except Exception as e:
print(f"Error downloading MP3: {e}")


#Loading song details from CSV
def load_song_details(csv_file):
song_details = []
with open(csv_file, 'r', newline='') as f:
reader = csv.reader(f)
next(reader) #skipping header
for row in reader:
song_details.append(row[:2])

return song_details


@app.get("/", response_class=HTMLResponse)
async def read_item(request: Request):
# Render the HTML template
return templates.TemplateResponse("index.html", {"request": request})


@app.post("/download_songs", response_class=HTMLResponse)
async def download_songs(request: Request, playlist_link: str = Form(...), userid: str = Form(...)):

print(userid)
print(playlist_link)
#Generating CSV file for the playlist
csv_file_path = generate_playlist_csv(playlist_link, userid)
print("CSV file is created")

user_folder = os.path.join("downloaded_songs", userid)
os.makedirs(user_folder, exist_ok=True)

song_details = load_song_details(csv_file_path)
downloaded_songs = []


for song_name, artist in song_details:
youtube_url = search_youtube(song_name, artist)
if youtube_url:
song_file = download_mp3(youtube_url, user_folder)
if song_file:
#encoded_file_name = urllib.parse.quote(song_file, safe="")
downloaded_songs.append(song_file)

response_data = {
"message": "Songs downloaded successfully!",
"user_folder": user_folder,
"songs": downloaded_songs
}

return JSONResponse(content=response_data)

@app.get("/download/{user_id}/{file_name}")
async def download_song(user_id: str, file_name: str):
user_folder = os.path.join("downloaded_songs", user_id)
file_path = os.path.join(user_folder, file_name)
return FileResponse(file_path, media_type='audio/mp3', filename=file_name)
Binary file added static/image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 40 additions & 0 deletions static/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
document.addEventListener("DOMContentLoaded", function(){
const form = document.getElementById("playlist-form");
form.addEventListener("submit", function(event){
event.preventDefault();
const formData = new FormData(form);
const playlistLink = formData.get("playlist_link");
const userid = generateUserId();
fetch("/download_songs", {
method: "POST",
body: new URLSearchParams({ playlist_link: playlistLink, userid: userid }),
headers:{
"Content-Type": "application/x-www-form-urlencoded",
},
})
.then(response => response.json())
.then(data => {
const userFolder = data.user_folder;
const songs = data.songs;
const downloadContainer = document.getElementById("downloads");
if(downloadContainer){
songs.forEach(song => {
const downloadLink = document.createElement("a");
downloadLink.href = `/download/${userid}/${song}`;
downloadLink.textContent = `Download ${song}`;
downloadContainer.appendChild(downloadLink);
downloadContainer.appendChild(document.createElement("br"));
});
} else {
console.error("Download container not found.");
}
})
.catch(error => {
console.error("Error: ", error);
});
});

function generateUserId(){
return Math.random().toString(36).substring(2,9);
}
});
101 changes: 101 additions & 0 deletions static/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
body {
font-family: Arial, sans-serif;
background-color: #f8f8f8;
margin: 0;
padding: 0;
}

h1 {
text-align: center;
color: #333;
margin-top: 20px;
}

form {
margin: 0 auto;
width: 300px;
background-color: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}

form label {
display: block;
margin-bottom: 10px;
color: #333;
}

form input[type="text"] {
width: calc(100% - 20px);
padding: 10px;
margin-bottom: 20px;
border: 1px solid #ccc;
border-radius: 4px;
}

form button[type="submit"] {
width: 100%;
padding: 10px;
background-color: #007bff;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s ease;
}

form button[type="submit"]:hover {
background-color: #0056b3;
}

#progress {
margin-top: 20px;
text-align: center;
}

.container {
display: flex;
justify-content: center;
align-items: center;
height: 200px;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
overflow: hidden;
}

.img {
max-width: 100%;
max-height: 100%;
object-fit: cover;
}

section#description {
background-color: #333;
padding: 20px;
border-radius: 8px;
margin: 20px auto;
max-width: 800px;
color: #fff;
}

section#description h2 {
color: #fff;
text-align: center;
margin-bottom: 20px;
}

section#description p {
line-height: 1.6;
margin-bottom: 10px;
}

section#description ol {
margin-left: 20px;
}

section#description ol li {
margin-bottom: 10px;
}

48 changes: 48 additions & 0 deletions templates/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Spotify2Mp3</title>
<link rel="stylesheet" href="{{ url_for('static', path='style.css') }}">
</head>
<body>
<div class="container">
<img src="/static/image.png" class="img">
</div>
<h1>Spotify2Mp3</h1>

<!-- Description Section -->
<section id="description">
<h2>How Spotify2Mp3 Works: </h2>
<p>Spotify2Mp3 is a tool that allows you to convert Spotify playlists into MP3 files for offline listening. Here's how it works:</p>
<ol>
<li>Enter the link to your Spotify playlist in the form provided.</li>
<li>Click the "Submit" button to initiate the conversion process.</li>
<li>Spotify2Mp3 will extract the song details from your playlist and search for them on YouTube.</li>
<li>Once found, it downloads the audio tracks from YouTube in MP3 format.</li>
<li>Then on the bottom-left links of the songs will appear, you can simply click on it to store it on your device.</li>
</ol>
<p>Enjoy your favorite Spotify playlists offline with Spotify2Mp3!</p>
</section>

<!-- Playlist Form -->
<form id="playlist-form">
<label for="playlist-link">Enter Playlist Link:</label><br>
<input type="text" id="playlist-link" name="playlist_link"><br><br>
<button type="submit">Submit</button>
</form>

<!-- Progress Section -->
<div id="progress">
<!-- Progress will be shown here -->
</div>

<!-- Downloads Section -->
<div id="downloads">
<!-- Download links will be appended here -->
</div>

<script src="{{ url_for('static', path='script.js') }}"></script>
</body>
</html>

0 comments on commit 3a0cdd8

Please sign in to comment.