165 lines
No EOL
4.9 KiB
Python
165 lines
No EOL
4.9 KiB
Python
# app.py
|
|
# Copyright (c) 2025 snfsx.xyz
|
|
# Licensed under the MIT License. See https://opensource.org/licenses/MIT
|
|
|
|
import os
|
|
import datetime
|
|
import requests
|
|
from flask import Flask, render_template, jsonify, request, send_from_directory
|
|
from dotenv import load_dotenv
|
|
from werkzeug.middleware.proxy_fix import ProxyFix
|
|
from flask_limiter import Limiter
|
|
from flask_limiter.util import get_remote_address
|
|
|
|
# Load environment variables from .env file
|
|
load_dotenv()
|
|
|
|
app = Flask(__name__)
|
|
|
|
app.wsgi_app = ProxyFix(
|
|
app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1
|
|
)
|
|
|
|
|
|
limiter = Limiter(
|
|
get_remote_address,
|
|
app=app,
|
|
default_limits=["300 per day", "50 per hour"],
|
|
storage_uri="memory://",
|
|
)
|
|
|
|
|
|
# --- Configuration from .env ---
|
|
|
|
lastfm_apik = os.getenv('LASTFM_API_KEY')
|
|
lastfm_usrname = os.getenv('LASTFM_USERNAME')
|
|
usrname = os.getenv('USER_NAME', 'User')
|
|
age = os.getenv('USER_AGE', '')
|
|
bio = os.getenv('USER_BIO', '#')
|
|
tg = os.getenv('USER_TELEGRAM_TAG')
|
|
bd = os.getenv('USER_BIRTHDAY', '')
|
|
github_usrn = os.getenv('GITHUB_USERNAME')
|
|
email = os.getenv('EMAIL_ADDRESS')
|
|
jabber = os.getenv('JABBER_ADDRESS')
|
|
ton = os.getenv('TON_ADDRESS')
|
|
ton_v = os.getenv('TON_VERSION')
|
|
favicon = os.getenv('FAVICON_TEXT')
|
|
|
|
# ---------------------------------
|
|
|
|
|
|
# ----------- Functions --------------
|
|
|
|
def get_lastfm_now_playing():
|
|
"""Fetches the currently playing track from Last.fm API."""
|
|
if not lastfm_apik or not lastfm_usrname:
|
|
return {'error': 'Last.fm API key or username not configured.'}
|
|
|
|
api_url = f"http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user={lastfm_usrname}&api_key={lastfm_apik}&format=json&limit=1"
|
|
|
|
try:
|
|
response = requests.get(api_url, timeout=10) # Added timeout
|
|
response.raise_for_status() # Raise an exception for bad status codes
|
|
data = response.json()
|
|
|
|
if 'recenttracks' in data and 'track' in data['recenttracks'] and data['recenttracks']['track']:
|
|
track_data = data['recenttracks']['track'][0]
|
|
is_now_playing = track_data.get('@attr', {}).get('nowplaying') == 'true'
|
|
|
|
if is_now_playing:
|
|
artist = track_data['artist']['#text']
|
|
name = track_data['name']
|
|
# Get the largest available image URL
|
|
image_url = next((img['#text'] for img in reversed(track_data.get('image', [])) if img['#text']), None)
|
|
# Construct a plausible song.link URL (accuracy may vary)
|
|
song_link = f"https://song.link/s/{requests.utils.quote(f'{name} {artist}')}"
|
|
|
|
|
|
return {
|
|
'playing': True,
|
|
'artist': artist,
|
|
'name': name,
|
|
'image_url': image_url,
|
|
'song_link': song_link
|
|
}
|
|
else:
|
|
return {'playing': False, 'message': 'Not listening anything right now.'}
|
|
else:
|
|
# Handle cases where user has no tracks or invalid response structure
|
|
return {'playing': False, 'message': 'No recent tracks found.'}
|
|
|
|
except requests.exceptions.RequestException as e:
|
|
print(f"Error fetching Last.fm data: {e}")
|
|
return {'error': f'Could not connect to Last.fm API: {e}'}
|
|
except Exception as e:
|
|
print(f"An unexpected error occurred: {e}")
|
|
return {'error': 'An unexpected error occurred while fetching Last.fm data.'}
|
|
|
|
# ------- end functions ------------
|
|
|
|
|
|
# ----------- Routes ----------------
|
|
@app.route('/')
|
|
def index():
|
|
"""Renders the main page."""
|
|
|
|
personal_info = {
|
|
'name': usrname,
|
|
'age': age,
|
|
'bio': bio,
|
|
'telegram': tg,
|
|
'birthday': bd,
|
|
'github_username': github_usrn,
|
|
'email': email,
|
|
'jabber': jabber,
|
|
'ton_version': ton_v,
|
|
'ton_address': ton,
|
|
'favicon': favicon,
|
|
'nickname': usrname.lower(),
|
|
'year': datetime.datetime.now().year
|
|
}
|
|
|
|
return render_template('index.html', info=personal_info)
|
|
|
|
|
|
|
|
@app.route('/api/v1/ip')
|
|
def ip_return():
|
|
|
|
ip = request.headers.get('X-Forwarded-For', request.remote_addr)
|
|
return jsonify({"ip": ip})
|
|
|
|
|
|
@app.route('/api/v1/now_playing')
|
|
@limiter.limit("1 per 5 second")
|
|
def api_now_playing():
|
|
"""API endpoint to get current Last.fm track."""
|
|
track_info = get_lastfm_now_playing()
|
|
return jsonify(track_info)
|
|
|
|
# -------------- End routes --------------
|
|
|
|
|
|
# ------------ Error handlers -----------
|
|
|
|
@app.errorhandler(429)
|
|
def ratelimit_error(e):
|
|
""" 429 handler """
|
|
return jsonify(
|
|
error="ratelimit_exceeded",
|
|
message="Too many requests",
|
|
), 429
|
|
|
|
|
|
@app.errorhandler(404)
|
|
def handle_not_found(error):
|
|
"""404 handler"""
|
|
app.logger.warning(f"404 Not Found: {request.path}")
|
|
return render_template('404.html'), 404
|
|
|
|
# ------------ End error handlers -------------
|
|
|
|
|
|
# Start
|
|
if __name__ == '__main__':
|
|
app.run(host='0.0.0.0', port=5000, debug=False) |