allow download raw project as json

This commit is contained in:
2025-12-21 19:38:40 +01:00
parent 7c24d9a7c5
commit 500a77761f
2 changed files with 49 additions and 4 deletions

View File

@ -391,7 +391,10 @@ class HipsterfyPlaylistItem(object):
class HipsterfyPlaylist(object):
def __init__(self, playlist_uri, hipsterfy:Hipsterfy):
def __init__(self, playlist_uri: str, hipsterfy:Hipsterfy, serialized_raw_data:List[Dict[str, Any]] = None ):
if serialized_raw_data:
self._tracks_data = [HipsterfyPlaylistItem(item) for item in serialized_raw_data]
return
self._playlist_uri = playlist_uri
self._hipsterfy = hipsterfy
self._tracks_data = []
@ -416,3 +419,8 @@ class HipsterfyPlaylist(object):
"""Returns the list of HipsterfyPlaylistItem objects representing the tracks in the playlist.
"""
return self._tracks_data
def get_raw_playlist_data(self) -> List[Dict[str, Any]]:
"""Returns the raw playlist data as a list of dictionaries.
"""
return [item._raw_data for item in self._tracks_data]

View File

@ -4,6 +4,7 @@ from io import BytesIO
from hipsterfy.hipsterfy import Hipsterfy, HipsterfyPlaylist, HipsterfyPlaylistItem, CardStyle
import qrcode
pn.extension("filedropper")
pn.extension("filedownload", "notifications", "location")
@ -12,13 +13,25 @@ pn.extension("filedownload", "notifications", "location")
def create_panel_page(hipsterfy: Hipsterfy, playlist_uri: str=None, root_url = None) -> pn.Template:
# create widgets
mode = pn.widgets.RadioButtonGroup(name='Input Mode', options=['Playlist URI', 'Upload JSON'], button_type='success', value='Playlist URI', sizing_mode='stretch_width')
playlist_uri = pn.widgets.TextInput(name='Playlist URI', value=playlist_uri or '', placeholder='Enter Spotify Playlist URI')
json_upload = pn.widgets.FileDropper(name='Upload Playlist JSON', accepted_filetypes=['application/json'], sizing_mode='stretch_width')
primary_item = pn.widgets.Select(name='Primary Item', options=HipsterfyPlaylistItem.get_available_properties(), value="release_year")
secondary_item = pn.widgets.Select(name='Secondary Item', options=HipsterfyPlaylistItem.get_available_properties(), value="title")
additional_items = pn.widgets.MultiChoice(name='Additional Items', options=HipsterfyPlaylistItem.get_available_properties(), value=["artists", "album", "popularity"])
card_style = pn.widgets.Select(name='Card Style', options=[style.value for style in CardStyle], value=CardStyle.FULL_ALBUM_COVER.value)
cards_per_row_widget = pn.widgets.IntSlider(name="Cards per Row in print", start=1, end=8, value=4, step=1)
def on_mode_change(event):
if mode.value == 'Playlist URI':
playlist_uri.visible = True
json_upload.visible = False
else:
playlist_uri.visible = False
json_upload.visible = True
mode.param.watch(on_mode_change, 'value')
on_mode_change(None) # Initial call to set visibility
pn.state.location.sync(playlist_uri, {"value": "playlist_uri"})
pn.state.location.sync(primary_item, {"value": "primary_item"})
pn.state.location.sync(secondary_item, {"value": "secondary_item"})
@ -39,6 +52,10 @@ def create_panel_page(hipsterfy: Hipsterfy, playlist_uri: str=None, root_url = N
label="Download Back Cards (HTML)", button_type="success", visible=False, filename="hipsterfy_back_cards.html", sizing_mode='stretch_width'
)
download_json_data_button = pn.widgets.FileDownload(
label="Download Playlist Data (JSON)", button_type="success", visible=False, filename="hipsterfy_raw_playlist_data.json", sizing_mode='stretch_width'
)
playlist_instructions = pn.pane.HTML(
"""
<div>
@ -110,6 +127,16 @@ def create_panel_page(hipsterfy: Hipsterfy, playlist_uri: str=None, root_url = N
download_back_html_button.callback = lambda: BytesIO(generate_html(cards_back, row_reverse=True))
download_back_html_button.visible = True
# Raw Playlist Data as JSON
def generate_playlist_json():
import json
uri = playlist_uri.value.strip()
hipsterfy_playlist = HipsterfyPlaylist(uri, hipsterfy)
data = hipsterfy_playlist.get_raw_playlist_data()
return json.dumps(data, indent=4).encode() # FileDownload erwartet Bytes
download_json_data_button.callback = lambda: BytesIO(generate_playlist_json())
download_json_data_button.visible = True
print_instructions.visible = True # Show print instructions after generating preview
pn.state.notifications.success("Download buttons updated successfully!. Download and print them from the sidebar")
@ -135,7 +162,15 @@ def create_panel_page(hipsterfy: Hipsterfy, playlist_uri: str=None, root_url = N
return
# create HipsterfyPlaylist instance
hipsterfy_playlist = HipsterfyPlaylist(uri, hipsterfy)
if mode.value == 'Upload JSON':
if len(json_upload.value) == 0:
pn.state.notifications.error("Please upload a valid JSON file containing playlist data.")
return
import json
raw_data = json.loads(list(json_upload.value.values())[0].decode())
hipsterfy_playlist = HipsterfyPlaylist(uri, hipsterfy, serialized_raw_data=raw_data)
else:
hipsterfy_playlist = HipsterfyPlaylist(uri, hipsterfy)
new_back_cards = []
new_front_cards = []
@ -168,6 +203,8 @@ def create_panel_page(hipsterfy: Hipsterfy, playlist_uri: str=None, root_url = N
create_preview_button.on_click(create_preview)
# Dynamischer QR-Code für die Player-App
def generate_qr_code_base64(url):
qr = qrcode.QRCode(box_size=4, border=2)
@ -199,9 +236,9 @@ def create_panel_page(hipsterfy: Hipsterfy, playlist_uri: str=None, root_url = N
title='Hipsterfy',
sidebar=[
player_qr_pane, # <-- Dynamischer QR-Code ganz oben in der Sidebar
playlist_instructions, playlist_uri, primary_item, secondary_item, additional_items, card_style,
playlist_instructions, mode, json_upload, playlist_uri, primary_item, secondary_item, additional_items, card_style,
cards_per_row_widget,
create_preview_button, download_front_html_button, download_back_html_button, print_instructions
create_preview_button, download_front_html_button, download_back_html_button, download_json_data_button, print_instructions
],
main=[pn.Row(front_cards_column, back_cards_column, sizing_mode='stretch_width')],
accent_base_color='indigo',