Giter VIP home page Giter VIP logo

modulate's Introduction

modulate

latest release build status

I like keeping my favorite Spotify tracks in playlists labeled by year (e.g. a playlist called "2023") but it's annoying to add tracks to playlists manually.

This tool allows you to transfer the tracks from one playlist to another on an interval. Most importantly, this also includes moving tracks from your liked/saved playlist, so you can press ❤️ and go on with your obviously busy life.

Once you connect your Spotify account and configure a watcher, it'll stay running and auto-transfer your tracks on the interval you choose (e.g. every hour/week/day). You can also configure it to just copy tracks instead of removing them. For example, you can keep your saved tracks synced to a collaborative playlist with your friends, or vice-versa.

View screenshot screenshot of app after configuring watchers

Usage

If you'd like to run it for yourself:

  1. Create a Spotify developer application
  2. Clone this repo
  3. cp .env.example .env
  4. Add Spotify creds to .env
  5. touch .data/modulate.db
  6. cargo run
  7. Go to localhost:4000, sign in, and configure

It will handle any number of connected users, as long as you add their email to your developer application via the dashboard.

Or, you could wait half a year for them to approve your application for public usage, only to deny you for rounding the corners of the playlist images.

Thanks

A few honorable mentions:

  • axum — to provide a web interface
  • oauth2 — for authenticating with Spotify API
  • askama — for HTML templating
  • rusqlite — for easily storing tokens and watchers
  • r2d2 — for managing the db connection

modulate's People

Contributors

zaknesler avatar

Stargazers

Lukas avatar

Watchers

 avatar

modulate's Issues

Add multiple watchers and playlist-playlist transferring

Kinda want to be able to transfer my Shazam tracks too! Let's allow playlist to playlist transferring, and as part of that, allow multiple watchers to be created.

Given an enum like this that represents a playlist type:

pub enum Playlist<'a> {
    Saved,
    WithId(PlaylistId<'a>), // or Public? Generic? idk of a good name for a regular playlist
}

Match on a from and to variable to transfer between saved -> with id (current) and with id -> with id (playlist to playlist).

pub async fn transfer(&self, from: Playlist<'_>, to: Playlist<'_>) -> crate::Result<bool> {
    Ok(match (from, to) {
        (Playlist::Saved, Playlist::WithId(playlist_id)) => todo!(),
        (Playlist::WithId(from_id), Playlist::WithId(to_id)) => todo!(),
        _ => unimplemented!(),
    })
}

Safely handle sync errors and add activity log

If one watcher fails for some reason (no permission to remove, rate limiting, playlist doesn't exist, etc.), it'll throw an error and kill the process of trying to sync everything...

Not sure what the best solution is here, it could be discarding errors when syncing (e.g. not ? on the result), but I still want a log of job attempts and their result state (success, error, etc).

This could also include job retrying or preventing a watcher from running again (if playlist is removed, the watcher should be moved to a disabled state or something.

All of these things should be visible to the user (job history, errors, successes, etc.), so I think adding an activity_log table would be a good start.

Add track filtering

For any transfers (but it makes the most sense for playlist-to-playlist), I'd like to be able to add a filter (e.g. where year >= 2023) to move to another playlist.

A more detailed example would be transferring "My Shazam Tracks" to a "2023" playlist, where you disable removing from the Shazam playlist, and instead just copy all tracks Shazamed since 2023.

Can probably just store these as JSON on the watchers table.

Transfer tracks in correct order

Tracks are read from the original playlist ordered newest to oldest, and so they are inserted into the target playlist in the wrong order.

Add nested error enums

e.g. for transfer errors, db errors, spotify errors, etc. then combine into one error for displaying on web.

Change sync interval per watcher

Add ability to change sync interval per watcher, still default 60 minutes. Store interval_mins and next_sync_at (or last_sync_at) on the watcher and update after every sync.

Interval options can be like 30 mins, 1 hour, 6 hours, 12 hours, 1 day, 1 week, 1 month?

Update sync thread to look up all watchers every minute to check which ones need to run.

Ability to sync from any playlist by URL

Maybe? Would be pretty sweet.

Obviously wouldn't allow for transferring (i.e. copying and them removing from source), but being able to keep your own public/private playlist in-sync with a Spotify official playlist or a random playlist would be useful.

Maybe a combo box for the playlist input? Select one of your own or paste a URL/ID? Stretching askama thin here.

Gracefully handle 429 errors

The app is now in review and I swear the Spotify staff is flooding the test site with requests 😭

Maybe handle 429 responses from Spotify API calls in some nicer way?

Keep track of playlist snapshots

Somewhat related to activity logs mentioned #23, it'd be nice to utilize the snapshot_id attribute returned when updating a Spotify playlist.

Snapshots act as version control for playlists, so when adding/removing tracks from playlists, it'd be nice to keep track of these. Both saving the snapshot_id after (and maybe before) a change, and also making updates to the same snapshot as described in the Spotify docs.

Ensure playlists not owned by user are not modifiable

  • Do not allow should_remove to be true when creating watcher where playlist_from is is not owned by the user
  • Do not allow creating watcher where playlist_to is not owned by user

This should still allow for copying (not transferring) from a playlist not owned by the user.

The SimplifiedPlaylist items that are returned from current_user_playlists do not have any kinda info about whether the user can edit the playlist... hmmm.

Only way I can think of is when a user selects a playlist, hit a new endpoint that checks whether the user can edit it? Another way would be to get full details of each playlist but that doesn't seem like a good idea.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.