]> littlesong.place Git - littlesongplace.git/commitdiff
Add missing duration field to update queue, other importer fixes
authorChris Fulljames <christianfulljames@gmail.com>
Mon, 19 Jan 2026 21:00:09 +0000 (16:00 -0500)
committerChris Fulljames <christianfulljames@gmail.com>
Mon, 19 Jan 2026 21:00:09 +0000 (16:00 -0500)
src/littlesongplace/dreams_importer.py
src/littlesongplace/songs.py
src/littlesongplace/sql/schema_revert.sql
src/littlesongplace/sql/schema_update.sql
src/littlesongplace/templates/dreams-importer.html
src/littlesongplace/templates/edit-song.html
test/test_dreams_importer.py
test/test_online.py
test/test_songs.py
test/utils.py

index 4f7d88a80ed3060c1074955b4d7973d267ce9b1a..82fd38bf7321459b0d26c3391e87d7ff88d93100 100644 (file)
@@ -75,16 +75,16 @@ def delete_from_queue(queueid):
     db.query("DELETE FROM import_queue WHERE queueid = ?", [queueid])
     current_app.logger.info(f"dreams_importer: Removed {queueid} from queue")
 
-def add_to_queue(songid, indreams_url):
+def add_to_queue(songid, indreams_url, duration):
     print(songid, indreams_url)
     timestamp = datetime.now(timezone.utc).isoformat()
     result = db.query(
         """
-        INSERT INTO import_queue (created, indreamsurl, songid, status)
-        VALUES (?, ?, ?, 0)
+        INSERT INTO import_queue (created, indreamsurl, songid, status, duration)
+        VALUES (?, ?, ?, 0, ?)
         RETURNING queueid
         """,
-        [timestamp, indreams_url, songid],
+        [timestamp, indreams_url, songid, duration],
         expect_one=True)
     queueid = result["queueid"]
 
index 562c61600b01c451331d2bf864201fa1fa1a144d..a0ec845ba069da422f5d130344c57c86773f36e3 100644 (file)
@@ -294,6 +294,22 @@ def validate_song_form():
 
     return error
 
+def duration_in_seconds(song_duration):
+    DEFAULT_DURATION = 180
+
+    if not ":" in song_duration:
+        return DEFAULT_DURATION
+
+    minutes, seconds = song_duration.split(":")
+
+    try:
+        minutes = int(minutes)
+        seconds = int(seconds)
+    except ValueError:
+        return DEFAULT_DURATION
+    
+    return (minutes * 60) + seconds
+
 def update_song():
     songid = request.args["songid"]
     try:
@@ -306,6 +322,7 @@ def update_song():
     title = request.form["title"]
     description = request.form["description"]
     upload_type = request.form["upload-type"]
+    song_duration = request.form["song-duration"]
     tags = [t.strip() for t in request.form["tags"].split(",") if t]
     collaborators = [c.strip() for c in request.form["collabs"].split(",") if c]
 
@@ -362,7 +379,8 @@ def update_song():
         if upload_type == "dreams" and url:
             if song_data["queueid"] is not None:
                 dreams_importer.delete_from_queue(song_data["queueid"])
-            dreams_importer.add_to_queue(songid, url)
+            duration = duration_in_seconds(song_duration)
+            dreams_importer.add_to_queue(songid, url, duration)
 
         db.commit()
         flash_and_log(f"Successfully updated '{title}'", "success")
@@ -375,6 +393,7 @@ def create_song():
     title = request.form["title"]
     description = request.form["description"]
     upload_type = request.form["upload-type"]
+    song_duration = request.form["song-duration"]
     tags = [t.strip() for t in request.form["tags"].split(",") if t]
     collaborators = [c.strip() for c in request.form["collabs"].split(",") if c]
     try:
@@ -423,7 +442,8 @@ def create_song():
                     [songid, collab])
 
             if upload_type == "dreams":
-                dreams_importer.add_to_queue(songid, url)
+                duration = duration_in_seconds(song_duration)
+                dreams_importer.add_to_queue(songid, url, duration)
 
             db.commit()
 
index fcb8d5309e21f264c4dc514f58e751fc316be5d5..19e44da062605fedfab03a6717841b5daf41e7ec 100644 (file)
@@ -1,3 +1,6 @@
+DROP VIEW IF EXISTS songs_view;
+ALTER TABLE songs DROP COLUMN queueid;
+DROP TABLE IF EXISTS import_queue;
 
 PRAGMA user_version = 7;
 
index bbb2b416d62a0a3980a6a72b7dd4d26c0150aea1..a19e4840f49342b81254e6cb3a1ca05393fc6329 100644 (file)
@@ -6,7 +6,8 @@ CREATE TABLE import_queue (
     created TEXT NOT NULL,
     indreamsurl TEXT NOT NULL,
     songid INTEGER NOT NULL REFERENCES songs(songid) ON DELETE CASCADE,
-    status INTEGER NOT NULL
+    status INTEGER NOT NULL,
+    duration INTEGER NOT NULL
 );
 
 DROP VIEW IF EXISTS songs_view;
index f23f9b3f03f0dd5fde76d6e1992ed9017ecc9452..c6274ffd53d69842b5f299a5ca5a0117cd223ec5 100644 (file)
@@ -4,29 +4,52 @@
 
 <h1>dreams importer</h1>
 
-<h2>how it works</h2>
+<h2>overview</h2>
 <p>
-The Dreams importer is a script that runs on my PC. It automates interactions
-with littlesong.place, indreams.me, and Dreams running on my PS5.
+The Dreams importer allows you to import your songs into LSP directly from
+Dreams!  It just requires a link to the element on
+<a href="https://indreams.me">indreams.me</a> and the length of the song (which
+are both entered on the usual song upload page).
 </p>
 <p>
-This means that my PC and PS5 need to be turned on and connected for the
-importer to work.  Generally, I will try to make sure it runs at least once a
-week (usually on weekends) when there are songs in the import queue.  I will
-also make sure to run it the day of the little song jam to upload any jam
-entries.
+The imports usually won't be instant.  I have to start the process manually, so
+it's most efficient for me to run it on large batches of songs.  It may take up
+to a week for the importer to run after you submit a song.  I'll usually run it
+on weekends, and especially on jam days right before the jam.
 </p>
 <p>
 If more than one weekend has passed and it still hasn't run, please send me an
 email at
 <a href="mailto:littlesongplace@gmail.com">littlesongplace@gmail.com</a>.
 </p>
+
+<h2>tips for imports</h2>
+For best results:
+<ul>
+    <li>Make sure your timeline doesn't loop if it isn't supposed to.</li>
+    <li>If it <i>is</i> supposed to loop, use the Fade Out option in the
+        importer to fade out the last 10 seconds of the recording.</li>
+    <li>Make sure your song sounds correct with all of the Dreams volume
+        settings turned all the way up - that's how it will be recorded.</li>
+    <li>When setting the duration in the importer, make sure to leave enough
+        time for any reverb/effect trails at the end.  If in doubt, add extra
+        time - any extra silence at the end will be removed automatically.</li>
+    <li>Remember that the Dreams timeline's duration timer will be wrong if you
+        use keyframes to change the tempo - make sure to add extra time to
+        compensate.</li>
+</ul>
+
+<h2>how it works</h2>
+<p>
+The Dreams importer is a script that runs on my PC. It automates interactions
+with littlesong.place, indreams.me, and Dreams running on my PS5.
+</p>
 <p>
 The script performs the following sequence for each song in the queue:
 <ol>
-    <li>Connect to LSP and get the song's InDreams URL</li>
-    <li>Load the InDreams URL and click the "Play Later" button</li>
-    <li>Remix the element in Dreams</li>
+    <li>Connect to LSP and get the song's indreams.me URL</li>
+    <li>Load the indreams.me URL and click the "Play Later" button</li>
+    <li>In Dreams (via remote play), remix the first element in the Play Later queue</li>
     <li>Play the song without recording to make sure all samples are loaded</li>
     <li>Play the song again, recording the audio</li>
     <li>Upload the song to LSP</li>
@@ -46,20 +69,4 @@ HDMI capture cards or the built-in screen recordings.)
 </i>
 </p>
 
-<h2>tips for imports</h2>
-For best results:
-<ul>
-    <li>Make sure your timeline doesn't loop if it isn't supposed to.</li>
-    <li>If it <i>is</i> supposed to loop, use the Fade Out option in the
-        importer to fade out the last 10 seconds of the recording.</li>
-    <li>Make sure your song sounds correct with all of the Dreams volume
-        settings turned all the way up - that's how it will be recorded.</li>
-    <li>When setting the duration in the importer, make sure to leave enough
-        time for any reverb/effect trails at the end.  If in doubt, add extra
-        time - any extra silence at the end will be removed automatically.</li>
-    <li>Remember that the Dreams timeline's duration timer will be wrong if you
-        use keyframes to change the tempo - make sure to add extra time to
-        compensate.</li>
-</ul>
-
 {% endblock %}
index 24951397a138f35ca183157853d92f6092c886c2..ea01b9f84c6c6b58a664b4d2e2546e4e91e15ff7 100644 (file)
@@ -118,7 +118,7 @@ function selectUploadMethod() {
         // Show dreams import URL box
         document.getElementById("song-url-container").hidden = false;
         document.getElementById("song-url").required = {% if song %}false{% else %}true{% endif %};
-        document.getElementById("song-url-label").innerText = "InDreams Element URL (element must be public!)"
+        document.getElementById("song-url-label").innerText = "indreams.me Element URL (element must be public!)"
 
         document.getElementById("song-file-container").hidden = true;
         document.getElementById("song-file").required = false;
index 3b81f3fde15c63a3a0c3dba585b2c7cd4181cdb2..5f46c54eb1f3d9a6303358c4110b127711d93db4 100644 (file)
@@ -7,7 +7,8 @@ def test_import_failure(client, user):
     upload_song(
         client, b"Queued for import from Dreams",
         upload_type="dreams",
-        song_url=TEST_URL)
+        song_url=TEST_URL,
+        song_duration="3:19")
     response = client.get(f"/users/user")
     assert b"[Hidden]" in response.data
     assert b"[Queue Pos: 1]" in response.data
@@ -17,6 +18,7 @@ def test_import_failure(client, user):
     assert response.json["next"]["userid"] == 1
     assert response.json["next"]["songid"] == 1
     assert response.json["next"]["queueid"] == 1
+    assert response.json["next"]["duration"] == 199
 
     # Now in progress
     response = client.get(f"/users/user")
@@ -56,6 +58,7 @@ def test_reset_queue_after_error(client, user):
     # In queue
     response = client.get("/dreams-importer/next-in-queue")
     assert response.json["next"]["indreamsurl"] == TEST_URL
+    assert response.json["next"]["duration"] == 180 # Default
 
     # No next item - but signals failure
     response = client.get("/dreams-importer/next-in-queue")
index 2683238cb2a42af0b540605f8c4654223688beb3..dde70518543b4ad3ad88c7648513045793286375 100644 (file)
@@ -22,6 +22,9 @@ def test_upload_and_delete_song(session):
             "description": "song description",
             "tags": "tag1, tag2",
             "collabs": "p1, p2",
+            "song-url": "",
+            "song-duration": "",
+            "upload-type": "file",
         },
     )
     response.raise_for_status()
@@ -46,7 +49,15 @@ def test_comments_and_activity(session):
     response = session.post(
         url("/upload-song"),
         files={"song-file": open(TEST_DATA/"sample-3s.mp3", "rb")},
-        data={"title": "song title", "description": "", "tags": "", "collabs": ""},
+        data={
+            "title": "song title",
+            "description": "",
+            "tags": "",
+            "collabs": "",
+            "song-url": "",
+            "song-duration": "",
+            "upload-type": "file",
+        },
     )
     response.raise_for_status()
     songs = _get_song_list_from_page(response.text)
@@ -91,7 +102,15 @@ def test_upload_song_from_youtube(session):
 
     response = session.post(
         url("/upload-song"),
-        data={"title": "yt-song", "description": "", "tags": "", "collabs": "", "song-url": "https://youtu.be/5e5Z6gZWiEs"},
+        data={
+            "title": "yt-song",
+            "description": "",
+            "tags": "",
+            "collabs": "",
+            "song-url": "https://youtu.be/5e5Z6gZWiEs",
+            "song-duration": "",
+            "upload-type": "yt",
+        },
     )
     response.raise_for_status()
     songs = _get_song_list_from_page(response.text)
index 2687dab3a5950df902c3aca0141ebff80d3031bd..44d4272afa40964f980a3e8a7e534202705f306e 100644 (file)
@@ -219,6 +219,8 @@ def test_update_song_other_users_song(client):
         "tags": "tag",
         "collabs": "collab",
         "upload-type": "file",
+        "song-url": "",
+        "song-duration": "",
     }
 
     response = client.post(f"/upload-song?songid=1", data=data)
index 57fb6415e5a9c51fda8fc39a601769f159acaed8..effa87accc6ea0c7c33e018682c10343f44f2f3e 100644 (file)
@@ -47,7 +47,8 @@ def create_user_song_and_playlist(client, playlist_type="private"):
 
 def upload_song(
         client, msg, error=False, songid=None, eventid=None,
-        user="user", userid=1, filename=TEST_DATA/"sample-3s.mp3", upload_type="file", song_url=None, **kwargs):
+        user="user", userid=1, filename=TEST_DATA/"sample-3s.mp3",
+        upload_type="file", song_url=None, song_duration=None, **kwargs):
 
     song_file = None
     if filename:
@@ -61,6 +62,7 @@ def upload_song(
         "collabs": "collab",
         "upload-type": upload_type,
         "song-url": song_url,
+        "song-duration": song_duration,
     }
     for k, v in kwargs.items():
         data[k] = v