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"]
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:
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]
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")
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:
[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()
+DROP VIEW IF EXISTS songs_view;
+ALTER TABLE songs DROP COLUMN queueid;
+DROP TABLE IF EXISTS import_queue;
PRAGMA user_version = 7;
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;
<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>
</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 %}
// 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;
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
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")
# 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")
"description": "song description",
"tags": "tag1, tag2",
"collabs": "p1, p2",
+ "song-url": "",
+ "song-duration": "",
+ "upload-type": "file",
},
)
response.raise_for_status()
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)
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)
"tags": "tag",
"collabs": "collab",
"upload-type": "file",
+ "song-url": "",
+ "song-duration": "",
}
response = client.post(f"/upload-song?songid=1", data=data)
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:
"collabs": "collab",
"upload-type": upload_type,
"song-url": song_url,
+ "song-duration": song_duration,
}
for k, v in kwargs.items():
data[k] = v