2424from . import lastfm
2525from . import sql as sql_commands
2626from . import export as export_command
27+
2728from .commands import stats as stats_command
2829from .commands import plays as plays_command
2930from .commands import albums as albums_command
3031from .commands import artists as artists_command
3132from .commands import tracks as tracks_command
3233import dateutil .parser
3334
35+ from .marimoui import app as marimo_app
36+
3437APP_NAME = "dev.pirateninja.scrobbledb"
3538console = Console ()
3639
@@ -649,19 +652,19 @@ def auth(auth, network):
649652def _ingest_no_batch (db , history , expected_count ):
650653 """
651654 Ingest tracks one at a time (original behavior).
652-
655+
653656 Args:
654657 db: sqlite_utils.Database instance
655658 history: Iterator of track data dictionaries
656659 expected_count: Expected number of tracks for progress bar
657-
660+
658661 Returns:
659662 Tuple of (min_timestamp, max_timestamp, track_count)
660663 """
661664 min_timestamp = None
662665 max_timestamp = None
663666 track_count = 0
664-
667+
665668 with Progress (
666669 SpinnerColumn (),
667670 TextColumn ("[progress.description]{task.description}" ),
@@ -677,40 +680,40 @@ def _ingest_no_batch(db, history, expected_count):
677680 lastfm .save_album (db , track ["album" ])
678681 lastfm .save_track (db , track ["track" ])
679682 lastfm .save_play (db , track ["play" ])
680-
683+
681684 # Track timestamp range
682685 timestamp = track ["play" ]["timestamp" ]
683686 if min_timestamp is None or timestamp < min_timestamp :
684687 min_timestamp = timestamp
685688 if max_timestamp is None or timestamp > max_timestamp :
686689 max_timestamp = timestamp
687690 track_count += 1
688-
691+
689692 progress .advance (task )
690-
693+
691694 return min_timestamp , max_timestamp , track_count
692695
693696
694697def _ingest_batch (db , history , expected_count , batch_size ):
695698 """
696699 Ingest tracks in batches for improved performance.
697-
700+
698701 Args:
699702 db: sqlite_utils.Database instance
700703 history: Iterator of track data dictionaries
701704 expected_count: Expected number of tracks for progress bar
702705 batch_size: Number of records to buffer before flushing
703-
706+
704707 Returns:
705708 Tuple of (min_timestamp, max_timestamp, track_count)
706709 """
707710 min_timestamp = None
708711 max_timestamp = None
709712 track_count = 0
710-
713+
711714 # Batch buffers
712715 batch = {"artists" : [], "albums" : [], "tracks" : [], "plays" : []}
713-
716+
714717 def flush_batch ():
715718 """Flush the current batch to the database."""
716719 if batch ["artists" ]:
@@ -722,7 +725,7 @@ def flush_batch():
722725 batch ["albums" ].clear ()
723726 batch ["tracks" ].clear ()
724727 batch ["plays" ].clear ()
725-
728+
726729 with Progress (
727730 SpinnerColumn (),
728731 TextColumn ("[progress.description]{task.description}" ),
@@ -739,24 +742,24 @@ def flush_batch():
739742 batch ["albums" ].append (track ["album" ])
740743 batch ["tracks" ].append (track ["track" ])
741744 batch ["plays" ].append (track ["play" ])
742-
745+
743746 # Track timestamp range
744747 timestamp = track ["play" ]["timestamp" ]
745748 if min_timestamp is None or timestamp < min_timestamp :
746749 min_timestamp = timestamp
747750 if max_timestamp is None or timestamp > max_timestamp :
748751 max_timestamp = timestamp
749752 track_count += 1
750-
753+
751754 # Flush batch when it reaches the batch size
752755 if len (batch ["plays" ]) >= batch_size :
753756 flush_batch ()
754-
757+
755758 progress .advance (task )
756-
759+
757760 # Flush any remaining records
758761 flush_batch ()
759-
762+
760763 return min_timestamp , max_timestamp , track_count
761764
762765
@@ -812,7 +815,18 @@ def flush_batch():
812815 help = "Disable actual execution of ingest and db mods" ,
813816)
814817@click .pass_context
815- def ingest (ctx , database , auth , since_date , until_date , limit , batch_size , no_batch , verbose , dry_run ):
818+ def ingest (
819+ ctx ,
820+ database ,
821+ auth ,
822+ since_date ,
823+ until_date ,
824+ limit ,
825+ batch_size ,
826+ no_batch ,
827+ verbose ,
828+ dry_run ,
829+ ):
816830 """
817831 Ingest play history from last.fm/libre.fm to a SQLite database.
818832
@@ -848,11 +862,17 @@ def ingest(ctx, database, auth, since_date, until_date, limit, batch_size, no_ba
848862 until_date = dateutil .parser .parse (until_date )
849863
850864 if since_date and until_date :
851- console .print (f"[green]Fetching scrobbles from { since_date .isoformat ()} to { until_date .isoformat ()} [/green]" )
865+ console .print (
866+ f"[green]Fetching scrobbles from { since_date .isoformat ()} to { until_date .isoformat ()} [/green]"
867+ )
852868 elif since_date :
853- console .print (f"[green]Fetching scrobbles since: { since_date .isoformat ()} [/green]" )
869+ console .print (
870+ f"[green]Fetching scrobbles since: { since_date .isoformat ()} [/green]"
871+ )
854872 elif until_date :
855- console .print (f"[green]Fetching scrobbles until: { until_date .isoformat ()} [/green]" )
873+ console .print (
874+ f"[green]Fetching scrobbles until: { until_date .isoformat ()} [/green]"
875+ )
856876 else :
857877 console .print ("[green]Fetching all scrobbles[/green]" )
858878
@@ -908,9 +928,13 @@ def ingest(ctx, database, auth, since_date, until_date, limit, batch_size, no_ba
908928
909929 # Ingest tracks using the appropriate mode
910930 if no_batch :
911- min_timestamp , max_timestamp , track_count = _ingest_no_batch (db , history , expected_count )
931+ min_timestamp , max_timestamp , track_count = _ingest_no_batch (
932+ db , history , expected_count
933+ )
912934 else :
913- min_timestamp , max_timestamp , track_count = _ingest_batch (db , history , expected_count , batch_size )
935+ min_timestamp , max_timestamp , track_count = _ingest_batch (
936+ db , history , expected_count , batch_size
937+ )
914938
915939 # Calculate elapsed time
916940 elapsed_time = time .time () - start_time
@@ -924,23 +948,25 @@ def ingest(ctx, database, auth, since_date, until_date, limit, batch_size, no_ba
924948 console .print (
925949 f"[green]✓[/green] Successfully ingested tracks to: [cyan]{ database } [/cyan]"
926950 )
927-
951+
928952 # Report timestamp range if any tracks were ingested
929953 if track_count > 0 and min_timestamp and max_timestamp :
930954 console .print (
931955 f"[cyan]Ingested { track_count } plays:[/cyan] "
932956 f"[yellow]{ min_timestamp .strftime ('%Y-%m-%d %H:%M:%S' )} [/yellow] to "
933957 f"[yellow]{ max_timestamp .strftime ('%Y-%m-%d %H:%M:%S' )} [/yellow]"
934958 )
935-
959+
936960 # Report elapsed time
937961 if elapsed_time >= 60 :
938962 minutes = int (elapsed_time // 60 )
939963 seconds = elapsed_time % 60
940- console .print (f"[cyan]Total time:[/cyan] [yellow]{ minutes } m { seconds :.1f} s[/yellow]" )
964+ console .print (
965+ f"[cyan]Total time:[/cyan] [yellow]{ minutes } m { seconds :.1f} s[/yellow]"
966+ )
941967 else :
942968 console .print (f"[cyan]Total time:[/cyan] [yellow]{ elapsed_time :.1f} s[/yellow]" )
943-
969+
944970 console .print (
945971 "[dim]Search index is automatically maintained and ready to use.[/dim]"
946972 )
@@ -1544,3 +1570,8 @@ def browse(database):
15441570 from .tui import run_browser
15451571
15461572 run_browser (database )
1573+
1574+
1575+ from marimo ._cli .cli import run as marimo_run
1576+
1577+ cli .add_command (marimo_run , name = "marimo" )
0 commit comments