Files
spotdl-auto/current
2025-12-07 14:35:40 +02:00

451 lines
13 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"nodes": {
"devenv": {
"locked": {
"dir": "src/modules",
"lastModified": 1764927628,
"owner": "cachix",
"repo": "devenv",
"rev": "247d7027f91368054fb0eefbd755a73d42b66fee",
"type": "github"
},
"original": {
"dir": "src/modules",
"owner": "cachix",
"repo": "devenv",
"type": "github"
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1764712249,
"owner": "edolstra",
"repo": "flake-compat",
"rev": "3b279e4317ccfa4865356387935310531357d919",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"git-hooks": {
"inputs": {
"flake-compat": "flake-compat",
"gitignore": "gitignore",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1765016596,
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "548fc44fca28a5e81c5d6b846e555e6b9c2a5a3c",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "git-hooks.nix",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
"git-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1762808025,
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "cb5e3fdca1de58ccbc3ef53de65bd372b48f567c",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1764580874,
"owner": "cachix",
"repo": "devenv-nixpkgs",
"rev": "dcf61356c3ab25f1362b4a4428a6d871e84f1d1d",
"type": "github"
},
"original": {
"owner": "cachix",
"ref": "rolling",
"repo": "devenv-nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"devenv": "devenv",
"git-hooks": "git-hooks",
"nixpkgs": "nixpkgs",
"pre-commit-hooks": [
"git-hooks"
]
}
}
},
"root": "root",
"version": 7
}
{ pkgs, lib, config, inputs, ... }: {
env.GREET = "SpotDL devenv";
packages = [pkgs.spotdl pkgs.python313Packages.spotipy pkgs.python313Packages.flask pkgs.openssl];
scripts.hello.exec = ''echo hello from $GREET ! '';
scripts.craftcerts.exec = ''
mkdir -p ssl # Use -p to avoid error if the directory exists
cd ssl
if [ ! -f ../openssl.cnf ]; then
echo "Please create 'openssl.cnf' in the parent directory."
exit 1
fi
openssl req -x509 -newkey rsa:2048 -keyout server.key -out server.cert -days 365 -nodes -config ../openssl.cnf >/dev/null
'';
scripts.download.exec = ''
while true; do
url=$(python ./geturl.py) # Capture the output of geturl.py
if [ $? -eq 0 ]; then
spotdl "$url"
break
fi
echo "Error downloading, retrying..."
sleep 2
done
'';
enterShell = ''
hello
craftcerts
download
'';
}
# yaml-language-server: $schema=https://devenv.sh/devenv.schema.json
inputs:
nixpkgs:
url: github:cachix/devenv-nixpkgs/rolling
# If you're using non-OSS software, you can set allowUnfree to true.
# allowUnfree: true
# If you're willing to use a package that's vulnerable
# permittedInsecurePackages:
# - "openssl-1.1.1w"
# If you have more than one devenv you can merge them
#imports:
# - ./backend
from flask import Flask, request, redirect
import spotipy
from spotipy.oauth2 import SpotifyOAuth
import subprocess
import os
import time
from datetime import datetime
app = Flask(__name__)
client_id = "c0020cc0e05245efb2ddb61b7045e4f2"
client_secret = "2e2e7c98f849403fbacc219c1f01c17d"
redirect_uri = "https://localhost:8888/callback"
sp_oauth = SpotifyOAuth(client_id=client_id, client_secret=client_secret, redirect_uri=redirect_uri, scope="playlist-modify-private user-library-read")
@app.route('/')
def index():
return "Welcome! <a href='/login'>Login to Spotify</a>"
@app.route('/login')
def login():
return redirect(sp_oauth.get_authorize_url())
@app.route('/callback')
def callback():
code = request.args.get('code')
token_info = sp_oauth.get_access_token(code)
access_token = token_info['access_token']
sp = spotipy.Spotify(auth=access_token)
print("Fetching liked songs...")
liked_songs = []
results = sp.current_user_saved_tracks()
while results:
for item in results['items']:
liked_songs.append(item['track']['id'])
if results['next']:
results = sp.next(results)
time.sleep(1)
else:
break
playlist_name = datetime.now().strftime("Liked Songs Collection - %Y-%m-%d %H-%M-%S")
user_id = sp.me()['id']
new_playlist = sp.user_playlist_create(user_id, playlist_name, public=False)
print(f"Created playlist: {playlist_name}")
for i in range(0, len(liked_songs), 100):
batch = liked_songs[i:i + 100]
sp.playlist_add_items(new_playlist['id'], batch)
print(f"Added {len(batch)} songs...")
time.sleep(1)
playlist_url = new_playlist['external_urls']['spotify']
print(f"Playlist URL: {playlist_url}")
# Write playlist URL for the download script
with open("last_playlist_url.txt", "w") as f:
f.write(playlist_url)
return f"{playlist_url}"
if __name__ == "__main__":
print("Starting Flask server...")
os.execvp('flask', [
'flask',
'run',
'--host=0.0.0.0',
'--port=8888',
'--cert=ssl/server.cert',
'--key=ssl/server.key'
])
from flask import Flask, request, redirect
import spotipy
from spotipy.oauth2 import SpotifyOAuth
import threading
import os
import sys
import time # Import time module
from datetime import datetime
app = Flask(__name__)
client_id = "c0020cc0e05245efb2ddb61b7045e4f2"
client_secret = "2e2e7c98f849403fbacc219c1f01c17d"
redirect_uri = "https://localhost:8888/callback"
sp_oauth = SpotifyOAuth(client_id=client_id, client_secret=client_secret, redirect_uri=redirect_uri, scope="playlist-modify-private user-library-read")
@app.route('/')
def index():
return "Welcome! <a href='/login'>Login to Spotify</a>"
@app.route('/login')
def login():
return redirect(sp_oauth.get_authorize_url())
@app.route('/callback')
def callback():
code = request.args.get('code')
token_info = sp_oauth.get_access_token(code)
access_token = token_info['access_token']
with open("access_token.txt", "w") as f:
f.write(access_token)
print("Authorization complete. You can close this window.", file=sys.stderr)
return "Authorization complete. You can close this window."
def create_playlist():
if not os.path.exists("access_token.txt"):
print("No access token found.", file=sys.stderr)
return
with open("access_token.txt", "r") as f:
access_token = f.read().strip()
sp = spotipy.Spotify(auth=access_token)
print("Fetching liked songs...", file=sys.stderr)
liked_songs = []
results = sp.current_user_saved_tracks()
while results:
for item in results['items']:
liked_songs.append(item['track']['id'])
if results['next']:
results = sp.next(results)
else:
break
playlist_name = datetime.now().strftime("Liked Songs Collection - %Y-%m-%d %H-%M-%S")
user_id = sp.me()['id']
new_playlist = sp.user_playlist_create(user_id, playlist_name, public=False)
print(f"Created playlist: {playlist_name}", file=sys.stderr)
for i in range(0, len(liked_songs), 100):
batch = liked_songs[i:i + 100]
sp.playlist_add_items(new_playlist['id'], batch)
print(f"Added {len(batch)} songs...", file=sys.stderr)
playlist_url = new_playlist['external_urls']['spotify']
print(f"Playlist URL: {playlist_url}", file=sys.stderr)
return playlist_url
def run_flask():
app.run(ssl_context=('ssl/server.cert', 'ssl/server.key'), host="0.0.0.0", port=8888)
def main():
# Start the Flask app in a background thread
flask_thread = threading.Thread(target=run_flask, daemon=True)
flask_thread.start()
# Inform the user to authorize access via the URL shown in the terminal
print("Please authorize access via the following URL:", sp_oauth.get_authorize_url())
# Wait until the access token is available
while not os.path.exists("access_token.txt"):
time.sleep(1) # Sleep for a while, then check again
# Now that we have the token, proceed with creating the playlist
playlist_url = create_playlist()
print(f"Playlist URL returned: {playlist_url}")
if __name__ == "__main__":
main()
[req]
default_bits = 2048
distinguished_name = req_distinguished_name
prompt = no
[req_distinguished_name]
C = US
ST = California
L = San Francisco
O = Example Company
OU = IT Department
CN = localhost
emailAddress = email@example.com
To implement HTTPS using Let's Encrypt and ngrok while modifying your Flask application, follow these structured steps:
## Step 1: Install and Set Up ngrok
1. **Download ngrok**:
- Go to the [ngrok website](https://ngrok.com/download) and download the appropriate version for your OS.
- Install ngrok by following the instructions on the site.
2. **Authenticate ngrok**:
- Sign up for a free account at ngrok.com.
- After signing up, youll receive an authtoken. Run the following command to set it up:
```bash
ngrok config add-authtoken <your_auth_token>
```
## Step 2: Modify Flask to Accept HTTPS
Update your Flask application to use ngrok to tunnel HTTPS traffic:
1. **Change `run_flask()` to bind to HTTP**:
This is so ngrok can handle the SSL termination. Update the endpoint by removing the `ssl_context`:
```python
def run_flask():
app.run(host="0.0.0.0", port=8888)
```
2. **Expose the Flask app via ngrok**:
You can run ngrok to expose your Flask app by executing:
```bash
ngrok http 8888
```
This will give you a public HTTPS URL that tunnels to your local Flask app.
## Step 3: Modify the Development Environment (devenv.nix)
Youll need to add the ngrok installation to your `devenv.nix` configuration, if it's not already installed.
1. **Edit `devenv.nix`**:
```nix
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
buildInputs = [
pkgs.ngrok
];
shellHook = ''
# Set up ngrok to run automatically
ngrok http 8888 &
'';
}
```
This snippet sets up ngrok to run in the background whenever you start your development environment.
## Step 4: Implement the PKI Chain in `geturl.py`
To implement an HTTPS PKI chain, consider using the Let's Encrypt certificate. For local development, you can't use Let's Encrypt directly without a publicly reachable domain, but you can still prepare your code as if you're using secure connections.
1. **Modify `geturl.py`**:
Assuming your application logic has not changed, implement a function to fetch the ngrok URL:
```python
import os
import requests
import threading
import time
def get_ngrok_url():
response = requests.get("http://localhost:4040/api/tunnels")
tunnels = response.json()["tunnels"]
for tunnel in tunnels:
if tunnel["name"] == "http":
return tunnel["public_url"]
return None
def create_playlist():
# Your existing code to create a playlist
...
def run_flask():
app.run(host="0.0.0.0", port=8888)
def main():
# Start Flask in a background thread
flask_thread = threading.Thread(target=run_flask, daemon=True)
flask_thread.start()
# Wait for ngrok to be ready
time.sleep(5) # Allow some time for ngrok to initialize
ngrok_url = get_ngrok_url()
print(f"Ngrok URL: {ngrok_url}")
print("Please authorize access via the following URL:", sp_oauth.get_authorize_url())
while not os.path.exists("access_token.txt"):
time.sleep(1)
playlist_url = create_playlist()
print(f"Playlist URL returned: {playlist_url}")
if __name__ == "__main__":
main()
```
In this code:
- `get_ngrok_url()` fetches the ngrok tunnel URL dynamically.
- You can then safely use this URL to inform other services of your HTTPS endpoint.
## Summary
This setup will let you run a local Flask application using HTTPS through an ngrok tunnel. You process the playlist creation and output the URL correctly while working in a secure environment. If you later transition to production, you can directly implement Let's Encrypt for your domain, maintaining the same architecture with minimal changes.