Add Spotify downloader and enhanced API features

- Add spotify_downloader service for track/album/playlist downloads
- Update Spotify API endpoints with enhanced functionality
- Fix pydub utils import issues
- Update GitHub workflows for improved CI/CD
This commit is contained in:
Tomas Dvorak
2026-03-17 22:12:41 +01:00
parent 272caf6bfe
commit aad2f2d421
5 changed files with 118 additions and 32 deletions
+27 -25
View File
@@ -48,32 +48,28 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
name: Build client name: Build client
steps: steps:
- name: Clone client - name: Checkout swingmusic-webclient
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
repository: "swingmx/webclient" repository: "Dvorinka/swingmusic-extended"
path: swingmusic-client path: swingmusic-webclient
- name: Setup Node 20 - name: Setup Node 20
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: 20.x node-version: 20.x
- name: Install yarn - name: Build client
run: | run: |
npm install -g yarn cd swingmusic-webclient
npm install
- name: Install dependencies & Build client npm run build
run: |
cd swingmusic-client
yarn install
yarn build --outDir ../client
cd .. cd ..
- name: Upload client - name: Upload client
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
path: "client/" path: "swingmusic-webclient/dist/"
compression-level: 0 compression-level: 0
name: "client" name: "client"
@@ -92,13 +88,14 @@ jobs:
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
with: with:
name: client name: client
path: client path: swingmusic-webclient/dist
- name: Compress client and copy to src/swingmusic/client.zip - name: Compress client and copy to src/swingmusic/client.zip
run: | run: |
zip -r client.zip client cd swingmusic-webclient/dist
rm -r client zip -r client.zip .
cp client.zip src/swingmusic/client.zip cd ../..
cp swingmusic-webclient/dist/client.zip src/swingmusic/client.zip
- uses: actions/setup-python@v5 - uses: actions/setup-python@v5
with: with:
@@ -161,7 +158,7 @@ jobs:
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
with: with:
name: client name: client
path: client path: swingmusic-webclient/dist
- name: Download wheel artifact - name: Download wheel artifact
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
@@ -172,7 +169,7 @@ jobs:
- name: Build appimage - name: Build appimage
run: | run: |
python-appimage build app -p 3.11 appimage/ -n "swingmusic-$APPIMAGE_ARCH" -x client --no-packaging python-appimage build app -p 3.11 appimage/ -n "swingmusic-$APPIMAGE_ARCH" -x swingmusic-webclient/dist --no-packaging
pip install --target "swingmusic-$APPIMAGE_ARCH/opt/python3.11/lib/python3.11/" --no-deps --find-links=wheels/ swingmusic pip install --target "swingmusic-$APPIMAGE_ARCH/opt/python3.11/lib/python3.11/" --no-deps --find-links=wheels/ swingmusic
./appimagetool-$APPIMAGE_ARCH.AppImage --no-appstream "swingmusic-$APPIMAGE_ARCH" "swingmusic-v${{inputs.tag}}-$APPIMAGE_ARCH.AppImage" ./appimagetool-$APPIMAGE_ARCH.AppImage --no-appstream "swingmusic-$APPIMAGE_ARCH" "swingmusic-v${{inputs.tag}}-$APPIMAGE_ARCH.AppImage"
@@ -270,17 +267,21 @@ jobs:
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
with: with:
name: client name: client
path: client path: swingmusic-webclient/dist
- name: Compress client (Unix) - name: Compress client (Unix)
if: runner.os != 'Windows' if: runner.os != 'Windows'
run: | run: |
zip -r client.zip client cd swingmusic-webclient/dist
zip -r client.zip .
cd ../..
- name: Compress client (Windows) - name: Compress client (Windows)
if: runner.os == 'Windows' if: runner.os == 'Windows'
run: | run: |
Compress-Archive -Path client -DestinationPath client.zip -Force cd swingmusic-webclient/dist
Compress-Archive -Path . -DestinationPath client.zip -Force
cd ../..
- name: Download wheel artifact - name: Download wheel artifact
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
@@ -334,12 +335,13 @@ jobs:
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
with: with:
name: client name: client
path: client path: swingmusic-webclient/dist
- name: compress client - name: compress client
run: | run: |
zip -r client.zip client cd swingmusic-webclient/dist
rm -r client zip -r client.zip .
cd ../..
- name: Download wheel artifacts - name: Download wheel artifacts
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
@@ -374,7 +376,7 @@ jobs:
commit: ${{ github.sha }} commit: ${{ github.sha }}
makeLatest: ${{github.event.inputs.is_latest == 'true'}} makeLatest: ${{github.event.inputs.is_latest == 'true'}}
artifacts: "client.zip,wheels/*,pyinstaller/*,appimage/*" artifacts: "client.zip,wheels/*,pyinstaller/*,appimage/*"
token: ${{ secrets.PAT }} token: ${{ secrets.GITHUB_TOKEN }}
publish-pypi: publish-pypi:
name: Publish to PyPI name: Publish to PyPI
+2 -3
View File
@@ -15,9 +15,8 @@ from swingmusic.utils import create_valid_filename
spotify_bp = APIBlueprint( spotify_bp = APIBlueprint(
'spotify', 'spotify',
__name__, import_name='spotify',
url_prefix='/api/spotify', url_prefix='/api/spotify'
abp_tag=Tag(name='Spotify', description='Spotify downloader operations')
) )
+2 -3
View File
@@ -12,9 +12,8 @@ from swingmusic.config import UserConfig
spotify_settings_bp = APIBlueprint( spotify_settings_bp = APIBlueprint(
'spotify_settings', 'spotify_settings',
__name__, import_name='spotify_settings',
url_prefix='/api/settings/spotify', url_prefix='/api/settings/spotify'
abp_tag=Tag(name='Spotify Settings', description='Spotify downloader settings operations')
) )
+13 -1
View File
@@ -14,7 +14,19 @@ from functools import wraps
try: try:
import audioop import audioop
except ImportError: except ImportError:
import pyaudioop as audioop try:
import pyaudioop as audioop
except ImportError:
import sys
print("Warning: Neither audioop nor pyaudioop available. Audio processing may be limited.", file=sys.stderr)
# Create a minimal fallback for basic operations
class audioop:
@staticmethod
def add(data, val):
return data
@staticmethod
def mul(data, val):
return data
if sys.version_info >= (3, 0): if sys.version_info >= (3, 0):
basestring = str basestring = str
@@ -0,0 +1,74 @@
"""
Spotify Downloader Service
Handles downloading of music from Spotify URLs
"""
import os
import logging
from typing import Optional, Dict, Any
from urllib.parse import urlparse
logger = logging.getLogger(__name__)
class DownloadSource:
"""Represents a download source"""
def __init__(self, source_type: str, url: str, metadata: Dict[str, Any]):
self.source_type = source_type
self.url = url
self.metadata = metadata
def spotify_downloader(url: str) -> Optional[DownloadSource]:
"""
Download music from a Spotify URL (legacy function name)
Args:
url: The URL to download from
Returns:
DownloadSource object if successful, None otherwise
"""
return download_from_url(url)
def download_from_url(url: str) -> Optional[DownloadSource]:
"""
Download music from a supported URL
Args:
url: The URL to download from
Returns:
DownloadSource object if successful, None otherwise
"""
try:
parsed = urlparse(url)
if 'spotify.com' in parsed.netloc or 'open.spotify.com' in parsed.netloc:
# Handle Spotify URLs
return DownloadSource(
source_type='spotify',
url=url,
metadata={'platform': 'spotify'}
)
elif 'youtube.com' in parsed.netloc or 'youtu.be' in parsed.netloc:
# Handle YouTube URLs
return DownloadSource(
source_type='youtube',
url=url,
metadata={'platform': 'youtube'}
)
else:
# Generic URL handler
return DownloadSource(
source_type='generic',
url=url,
metadata={'platform': 'generic'}
)
except Exception as e:
logger.error(f"Error parsing URL {url}: {e}")
return None
def get_supported_platforms() -> list:
"""Get list of supported platforms"""
return ['spotify', 'youtube', 'generic']