spoti-stream 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
spoti_fly/__init__.py ADDED
@@ -0,0 +1,8 @@
1
+ # spoti_fly/__init__.py
2
+ from .install_dependencies import install_scoop, install_ffmpeg
3
+
4
+ # Install Scoop and FFmpeg only if they are not already installed
5
+ install_scoop()
6
+ install_ffmpeg()
7
+
8
+
spoti_fly/converter.py ADDED
@@ -0,0 +1,15 @@
1
+ # spoti_fly/converter.py
2
+ import os
3
+ import subprocess
4
+
5
+ def convert_webm_to_mp3(webm_file_path, mp3_file_name, download_dir='songs'):
6
+ mp3_file_path = os.path.join(download_dir, mp3_file_name)
7
+ try:
8
+ # Suppressing FFmpeg logs by redirecting stdout and stderr
9
+ subprocess.run(['ffmpeg', '-i', webm_file_path, mp3_file_path],
10
+ check=True, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
11
+ print(f"Converted to MP3: {mp3_file_name}")
12
+ except subprocess.CalledProcessError as e:
13
+ print(f"Error converting {webm_file_path} to MP3: {e}")
14
+
15
+
@@ -0,0 +1,85 @@
1
+ # spoti_fly/downloader.py
2
+
3
+ import os
4
+ import yt_dlp
5
+ from .converter import convert_webm_to_mp3
6
+ import re
7
+
8
+ def sanitize_filename(filename):
9
+ return re.sub(r'[\\/*?:"<>|]', '_', filename) # Replaces problematic characters with underscore
10
+
11
+ def download_song(song_name, artist_name, download_dir='songs'):
12
+ query = f"{song_name} {artist_name} audio"
13
+ sanitized_song_name = sanitize_filename(f"{song_name} by {artist_name}")
14
+ mp3_file_name = f"{sanitized_song_name}.mp3"
15
+ mp3_file_path = os.path.join(download_dir, mp3_file_name)
16
+
17
+ if os.path.exists(mp3_file_path):
18
+ print(f"'{song_name} by {artist_name}' is already downloaded as MP3. Skipping...")
19
+ return
20
+
21
+ ydl_opts = {
22
+ 'format': 'bestaudio[ext=webm]/bestaudio',
23
+ 'outtmpl': os.path.join(download_dir, f"{sanitized_song_name}.webm"),
24
+ 'noplaylist': True,
25
+ 'quiet': True # Suppress yt-dlp logging
26
+ }
27
+
28
+ with yt_dlp.YoutubeDL(ydl_opts) as ydl:
29
+ try:
30
+ print(f"Searching and downloading: {query}")
31
+ ydl.download([f"ytsearch1:{query}"])
32
+ print(f"Downloaded: {mp3_file_name}")
33
+
34
+ # Convert downloaded .webm to .mp3
35
+ convert_webm_to_mp3(os.path.join(download_dir, f"{sanitized_song_name}.webm"), mp3_file_name, download_dir)
36
+
37
+ # Remove the .webm file after conversion
38
+ webm_file_path = os.path.join(download_dir, f"{sanitized_song_name}.webm")
39
+ if os.path.exists(webm_file_path):
40
+ os.remove(webm_file_path)
41
+
42
+ except yt_dlp.utils.DownloadError as e:
43
+ print(f"Download error for {song_name} by {artist_name}: {e}")
44
+ except Exception as e:
45
+ print(f"An error occurred while downloading {song_name} by {artist_name}: {e}")
46
+
47
+ def download_songs_from_playlist(sp, playlist_id, playlist_name, download_dir='songs'):
48
+ from .spotify_utils import fetch_songs_from_playlist, save_songs_to_csv
49
+ songs = fetch_songs_from_playlist(sp, playlist_id)
50
+ if songs:
51
+ save_songs_to_csv(songs, playlist_name)
52
+ for song_name, artist_name in songs:
53
+ download_song(song_name, artist_name, download_dir)
54
+ else:
55
+ print(f"No songs found in playlist: {playlist_name}")
56
+
57
+ def download_songs_from_csv(csv_file_path, download_dir='songs'):
58
+ import csv
59
+ try:
60
+ with open(csv_file_path, newline='', encoding='utf-8') as csvfile:
61
+ reader = csv.DictReader(csvfile)
62
+ for row in reader:
63
+ song_name = row.get('Song Name')
64
+ artist_name = row.get('Artist Name')
65
+ if song_name and artist_name:
66
+ download_song(song_name, artist_name, download_dir)
67
+ except FileNotFoundError:
68
+ print(f"File not found: {csv_file_path}")
69
+ except Exception as e:
70
+ print(f"An error occurred while reading the CSV file: {e}")
71
+
72
+ def download_songs_from_txt(txt_file_path, download_dir='songs'):
73
+ try:
74
+ with open(txt_file_path, 'r', encoding='utf-8') as txtfile:
75
+ for line in txtfile:
76
+ song_info = line.strip().split('-')
77
+ if len(song_info) == 2:
78
+ song_name, artist_name = song_info
79
+ download_song(song_name.strip(), artist_name.strip(), download_dir)
80
+ else:
81
+ print(f"Invalid format in TXT file: {line}")
82
+ except FileNotFoundError:
83
+ print(f"File not found: {txt_file_path}")
84
+ except Exception as e:
85
+ print(f"An error occurred while reading the TXT file: {e}")
@@ -0,0 +1,40 @@
1
+ import subprocess
2
+ import os
3
+
4
+ def is_installed(command):
5
+ """Check if a command exists on the system."""
6
+ try:
7
+ subprocess.run(command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, shell=True)
8
+ return True
9
+ except Exception:
10
+ return False
11
+
12
+ def install_scoop():
13
+ """Install Scoop if it's not already installed."""
14
+ if is_installed('scoop'):
15
+ #print("Scoop is already installed.")
16
+ return
17
+ try:
18
+ # Suppress output and errors using DEVNULL
19
+ subprocess.run(
20
+ 'powershell -Command "Set-ExecutionPolicy RemoteSigned -scope CurrentUser; iwr -useb get.scoop.sh | iex"',
21
+ shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
22
+ )
23
+ print("Scoop installed successfully.")
24
+ except subprocess.CalledProcessError:
25
+ print("Failed to install Scoop.")
26
+
27
+ def install_ffmpeg():
28
+ """Install FFmpeg using Scoop if it's not already installed."""
29
+ if is_installed('ffmpeg'):
30
+ #print("FFmpeg is already installed.")
31
+ return
32
+ try:
33
+ # Suppress output and errors using DEVNULL
34
+ subprocess.run(
35
+ 'powershell -Command "scoop install ffmpeg"',
36
+ shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
37
+ )
38
+ print("FFmpeg installed successfully.")
39
+ except subprocess.CalledProcessError:
40
+ print("Failed to install FFmpeg.")
spoti_fly/main.py ADDED
@@ -0,0 +1,86 @@
1
+ # spoti_fly/main.py
2
+ import os
3
+ from .spotify_utils import authenticate_spotify, get_user_playlists, fetch_songs_from_playlist
4
+ from .downloader import download_songs_from_playlist, download_songs_from_csv, download_songs_from_txt, download_song
5
+
6
+ def main():
7
+ print("\n[INFO] Welcome to SpotiFly! ")
8
+ print("Download and listen to non-stop Spotify music with our tool.")
9
+ print("Music is an art which reach your soul to pacify it..... :)")
10
+ print("For more information visit: https://github.com/mehmoodulhaq570")
11
+ print(" =---------------------------------= ")
12
+
13
+ # Check for existing Spotify credentials
14
+ sp = authenticate_spotify()
15
+
16
+ while True:
17
+ print("\nWhat would you like to do?")
18
+ print("1. Use a Spotify playlist")
19
+ print("2. Provide your own CSV or TXT file")
20
+ print("3. Manually type in song names")
21
+ print("4. Exit from SpotiFly")
22
+
23
+ choice = input("Please enter 1, 2, 3 or 4: ").strip()
24
+
25
+ if choice == '1':
26
+ playlists = get_user_playlists(sp)
27
+
28
+ if playlists:
29
+ print("Your Playlists:")
30
+ for i, playlist in enumerate(playlists):
31
+ print(f"{i + 1}. {playlist['name']} (ID: {playlist['id']})")
32
+ else:
33
+ print("No playlists found or an error occurred.")
34
+
35
+ try:
36
+ selected_index = int(input("Select a playlist by number: ")) - 1
37
+ if selected_index < 0 or selected_index >= len(playlists):
38
+ print("Invalid selection. Please enter a valid playlist number.")
39
+ continue
40
+
41
+ selected_playlist = playlists[selected_index]
42
+ selected_playlist_id = selected_playlist['id']
43
+ selected_playlist_name = selected_playlist['name']
44
+
45
+ download_songs_from_playlist(sp, selected_playlist_id, selected_playlist_name)
46
+
47
+ except ValueError:
48
+ print("Invalid input. Please enter a valid number.")
49
+ except Exception as e:
50
+ print(f"An error occurred: {e}")
51
+
52
+ elif choice == '2':
53
+ file_path = input("Enter the full path to your CSV or TXT file: ").strip()
54
+
55
+ if file_path.lower().endswith('.csv'):
56
+ download_songs_from_csv(file_path)
57
+ elif file_path.lower().endswith('.txt'):
58
+ download_songs_from_txt(file_path)
59
+ else:
60
+ print("Invalid file format. Please provide a .csv or .txt file.")
61
+
62
+ elif choice == '3':
63
+ while True:
64
+ song_name = input("Enter the song name (or 'q' to stop): ").strip()
65
+ if song_name.lower() == 'q':
66
+ break
67
+ artist_name = input(f"Enter the artist name for '{song_name}': ").strip()
68
+ download_song(song_name, artist_name)
69
+
70
+ elif choice == '4':
71
+ print("\n *-------------------------------* ")
72
+ print("Thank you for using SpotiFly Music! Goodbye!")
73
+ print(" *-------------------------------* ")
74
+ break
75
+
76
+ else:
77
+ print("Invalid choice. Please enter 1, 2, 3 or 4.")
78
+
79
+ if input("Do you want to continue? (y/n): ").strip().lower() != 'y':
80
+ print("\n *-------------------------------* ")
81
+ print("Thank you for using SpotiFly Music! Goodbye!")
82
+ print(" *-------------------------------* ")
83
+ break
84
+
85
+ if __name__ == '__main__':
86
+ main()
@@ -0,0 +1,72 @@
1
+ # spoti_fly/spotify_utils.py
2
+ import spotipy
3
+ from spotipy.oauth2 import SpotifyOAuth
4
+
5
+ def save_credentials_to_file(client_id, client_secret, file_path='spotify_credentials.txt'):
6
+ try:
7
+ with open(file_path, 'w') as f:
8
+ f.write(f"{client_id}\n{client_secret}\n")
9
+ print(f"Spotify credentials saved to {file_path}")
10
+ except Exception as e:
11
+ print(f"An error occurred while saving credentials: {e}")
12
+
13
+ def read_credentials_from_file(file_path='spotify_credentials.txt'):
14
+ try:
15
+ with open(file_path, 'r') as f:
16
+ lines = f.readlines()
17
+ client_id = lines[0].strip()
18
+ client_secret = lines[1].strip()
19
+ return client_id, client_secret
20
+ except Exception as e:
21
+ print(f"An error occurred while reading credentials: {e}")
22
+ return None, None
23
+
24
+ def authenticate_spotify():
25
+ client_id, client_secret = read_credentials_from_file()
26
+
27
+ if client_id is None or client_secret is None:
28
+ client_id = input("Enter your Spotify Client ID: ")
29
+ client_secret = input("Enter your Spotify Client Secret: ")
30
+ save_credentials_to_file(client_id, client_secret)
31
+
32
+ REDIRECT_URI = 'http://localhost:8888/callback'
33
+ scope = 'playlist-read-private user-library-read'
34
+ sp = spotipy.Spotify(auth_manager=SpotifyOAuth(client_id=client_id,
35
+ client_secret=client_secret,
36
+ redirect_uri=REDIRECT_URI,
37
+ scope=scope))
38
+ return sp
39
+
40
+ def get_user_playlists(sp):
41
+ try:
42
+ playlists = sp.current_user_playlists()
43
+ return playlists['items']
44
+ except Exception as e:
45
+ print(f"An error occurred while fetching playlists: {e}")
46
+ return []
47
+
48
+ def fetch_songs_from_playlist(sp, playlist_id):
49
+ tracks = []
50
+ try:
51
+ results = sp.playlist_items(playlist_id, limit=100)
52
+ while results:
53
+ for item in results['items']:
54
+ track = item['track']
55
+ tracks.append([track['name'], track['artists'][0]['name']])
56
+ if results['next'] is not None:
57
+ results = sp.next(results)
58
+ else:
59
+ break
60
+ except Exception as e:
61
+ print(f"An error occurred while fetching songs from the playlist: {e}")
62
+ return tracks
63
+
64
+ def save_songs_to_csv(songs, playlist_name):
65
+ import csv
66
+ from .downloader import sanitize_filename
67
+ filename = sanitize_filename(f"{playlist_name}.csv")
68
+ with open(filename, mode='w', newline='', encoding='utf-8') as file:
69
+ writer = csv.writer(file)
70
+ writer.writerow(['Song Name', 'Artist Name'])
71
+ writer.writerows(songs)
72
+ print(f"Playlist saved to: {filename}")
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Mehmood Ul Haq
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
@@ -0,0 +1,42 @@
1
+ Metadata-Version: 2.1
2
+ Name: spoti_stream
3
+ Version: 0.1.0
4
+ Summary: A tool to download Spotify playlist songs using YouTube
5
+ Home-page: https://github.com/mehmoodulhaq570/SpotiStream
6
+ Author: Mehmood Ul Haq
7
+ Author-email: mehmoodulhaq1040@gmail.com
8
+ License: MIT
9
+ Project-URL: Documentation, https://github.com/mehmoodulhaq570/SpotiStream#readme
10
+ Project-URL: Source, https://github.com/mehmoodulhaq570/SpotiStream
11
+ Project-URL: Bug Tracker, https://github.com/mehmoodulhaq570/SpotiStream/issues
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Requires-Python: >=3.6
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE.txt
18
+ Requires-Dist: spotipy >=2.19.0
19
+ Requires-Dist: yt-dlp >=2021.12.1
20
+ Requires-Dist: moviepy >=1.0.3
21
+ Requires-Dist: pydub >=0.25.1
22
+
23
+ # SpotiStream
24
+
25
+ **SpotiStream** is a Python package that allows you to download songs from Spotify playlists by fetching song information and downloading the corresponding audio from YouTube. The songs are saved in MP3 format.
26
+
27
+ ## Features
28
+
29
+ - Authenticate with Spotify using OAuth to access playlists.
30
+ - Fetch and download songs from Spotify playlists.
31
+ - Save song information in a CSV file for easy access.
32
+ - Convert downloaded YouTube audio from WebM to MP3 format.
33
+ - Download songs directly from a user-provided CSV file.
34
+ - Handles credential storage and reuse.
35
+
36
+ ## Installation
37
+
38
+ 1. Clone the repository or install the package:
39
+
40
+ ```bash
41
+ git clone https://github.com/your-repo/spoti_stream.git
42
+ cd spoti_stream
@@ -0,0 +1,12 @@
1
+ spoti_fly/__init__.py,sha256=ejDT6N39W9DrhRRaqYOdQpIuhSsxxsTkHUMyfkjQp-M,190
2
+ spoti_fly/converter.py,sha256=FnMPU6IF-_cKLWoVGwwD5965rkwMTi_3OTmeONalgSw,595
3
+ spoti_fly/downloader.py,sha256=Olc6Na6_ncV3VmTCTHFcQUh4OlGCC4z5siB-mGhITpw,3548
4
+ spoti_fly/install_dependencies.py,sha256=yzwsbX6L7Pta-os5o9N8dQqesVnNjArAz3uCoWqcBbw,1452
5
+ spoti_fly/main.py,sha256=OrbDICoW486kYoSU9idEpZnNTV6wemxW66Tx8kzN_24,3520
6
+ spoti_fly/spotify_utils.py,sha256=9ehwUiepM2ZCK7VG6E-QwBL1_cHTagaJdG1ASqGakWY,2778
7
+ spoti_stream-0.1.0.dist-info/LICENSE.txt,sha256=qIVZzvyU9EhEIU_vKRQ9RCDb7L7FcDmNCXDZR1s3uV0,1072
8
+ spoti_stream-0.1.0.dist-info/METADATA,sha256=Eh1KZT00ku4SWMLs1n8712TAx-YAlWn21JXpOv-j0WU,1602
9
+ spoti_stream-0.1.0.dist-info/WHEEL,sha256=Z4pYXqR_rTB7OWNDYFOm1qRk0RX6GFP2o8LgvP453Hk,91
10
+ spoti_stream-0.1.0.dist-info/entry_points.txt,sha256=0muJlf-Id2OFknCd_zwoBvnfvhtRaUjrPZKsi5DqW5w,53
11
+ spoti_stream-0.1.0.dist-info/top_level.txt,sha256=dPL64yciCl8S94MbMkcnD-NLlUvkYLRWZwvuY9j8iVc,10
12
+ spoti_stream-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (70.3.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ spoti_fly = spoti_stream.main:main
@@ -0,0 +1 @@
1
+ spoti_fly