diff --git a/Cargo.lock b/Cargo.lock index 8b7055a..e763805 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -857,9 +857,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.113" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eef78b64d87775463c549fbd80e19249ef436ea3bf1de2a1eb7e717ec7fab1e9" +checksum = "b0005d08a8f7b65fb8073cb697aa0b12b631ed251ce73d862ce50eeb52ce3b50" [[package]] name = "libdbus-sys" diff --git a/Cargo.toml b/Cargo.toml index 5ef181b..fa6b610 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,8 @@ edition = "2021" authors = ["NGnius (Graham) "] description = "Music Playlist Scripting language (MPS)" license = "LGPL-2.1-only OR GPL-2.0-or-later" +repository = "https://github.com/NGnius/mps" +keywords = ["audio", "playlist", "scripting", "language"] readme = "README.md" [workspace] diff --git a/README.md b/README.md index 8d354f6..95e29f9 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # mps -A language all about interation to play your music files. +A language all about iteration to play your music files. This project implements the interpreter (mps-interpreter), music player (mps-player), and CLI interface for MPS (root). The CLI interface includes a REPL for running scripts. The REPL interactive mode also provides more details about using MPS through the `?help` command. @@ -24,7 +24,7 @@ One day I'll add pretty REPL example pictures and some script files... **I thought it would be fun**. I also wanted to be able to play my music without having to be at the whim of someone else's algorithm (and music), and playing just by album or artist was getting boring. I also thought designing a language specifically for iteration would be a novel approach to a language (though every approach is a novel approach for me). ### What is MPS? -**Music Playlist Script (MPS) is technically a query language for music files.** It uses an (auto-generated) SQLite3 database for SQL queries and can also directly query the filesystem. Queries can be filtered and extended by using filters and functions built-in to MPS (see mps-interpreter's README.md). +**Music Playlist Script (MPS) is technically a query language for music files.** It uses an (auto-generated) SQLite3 database for SQL queries and can also directly query the filesystem. Queries can be modified by using filters, functions, and sorters built-in to MPS (see mps-interpreter's README.md). ### Is MPS a scripting language? **No**. Technically, it was designed to be one, but it doesn't meet the requirements of a scripting language (yet). One day, I would like it be Turing-complete and then it could be considered a scripting language. At the moment it is barely a query language. diff --git a/mps-interpreter/README.md b/mps-interpreter/README.md index 6d1de17..6de0921 100644 --- a/mps-interpreter/README.md +++ b/mps-interpreter/README.md @@ -124,5 +124,16 @@ Repeat the iterable count times, or infinite times if count is omitted. Retrieve all files from a folder, matching a regex pattern. +### Sorters +Operations to sort the items in an iterable: iterable~(sorter) OR iterable.sort(sorter) + +#### field -- e.g. iterable~(filename) + +Sort by a MpsItem field. Valid field names change depending on what information is available when the MpsItem is populated, but usually title, artist, album, genre, track, filename are valid fields. Items with a missing/incomparable fields will be sorted to the end. + +#### distance bliss -- e.g. iterable~(distance bliss) + +Sort by the distance (similarity) between songs. Songs which are more similar (lower distance) to the first song in the iterator will be placed closer to the first song, while less similar songs will be sorted to the end. This uses the [bliss music analyser](https://github.com/polochon-street/bliss-rs), which is a very slow operation and can cause music playback interruptions for large iterators. + License: LGPL-2.1-only OR GPL-2.0-or-later diff --git a/mps-interpreter/src/lib.rs b/mps-interpreter/src/lib.rs index d9617e6..8417e69 100644 --- a/mps-interpreter/src/lib.rs +++ b/mps-interpreter/src/lib.rs @@ -122,6 +122,17 @@ //! //! Retrieve all files from a folder, matching a regex pattern. //! +//! ## Sorters +//! Operations to sort the items in an iterable: iterable~(sorter) OR iterable.sort(sorter) +//! +//! ### field -- e.g. iterable~(filename) +//! +//! Sort by a MpsItem field. Valid field names change depending on what information is available when the MpsItem is populated, but usually title, artist, album, genre, track, filename are valid fields. Items with a missing/incomparable fields will be sorted to the end. +//! +//! ### distance bliss -- e.g. iterable~(distance bliss) +//! +//! Sort by the distance (similarity) between songs. Songs which are more similar (lower distance) to the first song in the iterator will be placed closer to the first song, while less similar songs will be sorted to the end. This uses the [bliss music analyser](https://github.com/polochon-street/bliss-rs), which is a very slow operation and can cause music playback interruptions for large iterators. +//! mod context; mod interpretor; diff --git a/src/help.rs b/src/help.rs index a895855..5719354 100644 --- a/src/help.rs +++ b/src/help.rs @@ -2,7 +2,7 @@ pub const HELP_STRING: &str = "This language is all about iteration. Almost everything is an iterator or operates on iterators. By default, any operation which is not an assignment will cause the script runner to handle (play/save) the items which that statement contains. -To view the currently-supported operations, try ?functions and ?filters"; +To view the currently-supported operations, try ?functions, ?filters, or ?sorters"; pub const FUNCTIONS: &str = "FUNCTIONS (?functions) @@ -43,7 +43,7 @@ Operations to reduce the items in an iterable: iterable.(filter) field > something field <= something field < something -- e.g. iterable.(title == `Romantic Traffic`) - Compare all items, keeping only those that match the condition. Valid field names are those of the MpsMusicItem (title, artist, album, genre, track, etc.), though this will change when proper object support is added. Optionally, a ? or ! can be added to the end of the field name to skip items whose field is missing/incomparable, or keep all items whose field is missing/incomparable (respectively). + Compare all items, keeping only those that match the condition. Valid field names change depending on what information is available when the MpsItem is populated, but usually title, artist, album, genre, track, filename are valid fields. Optionally, a ? or ! can be added to the end of the field name to skip items whose field is missing/incomparable, or keep all items whose field is missing/incomparable (respectively). start..end -- e.g. iterable.(0..42) Keep only the items that are at the start index up to the end index. Start and/or end may be omitted to start/stop at the iterable's existing start/end (respectively). This stops once the end condition is met, leaving the rest of the iterator unconsumed. @@ -62,3 +62,13 @@ Operations to reduce the items in an iterable: iterable.(filter) if filter: operation1 else operation2 -- e.g. iterable.(if title == `Romantic Traffic`: repeat(item, 2) else item.()) Replace items matching the filter with operation1 and replace items not matching the filter with operation2. The `else operation2` part may be omitted to preserve items not matching the filter. To perform operations with the current item, use the special variable `item`. The replacement filter may not contain || -- instead, use multiple filters chained together."; + +pub const SORTERS: &str = +"SORTERS (?sorters) +Operations to sort the items in an iterable: iterable~(sorter) OR iterable.sort(sorter) + + field -- e.g. iterable~(filename) + Sort by a MpsItem field. Valid field names change depending on what information is available when the MpsItem is populated, but usually title, artist, album, genre, track, filename are valid fields. Items with a missing/incomparable fields will be sorted to the end. + + distance bliss -- e.g. iterable~(distance bliss) + Sort by the distance (similarity) between songs. Songs which are more similar (lower distance) to the first song in the iterator will be placed closer to the first song, while less similar songs will be sorted to the end. This uses the bliss music analyser, which is a very slow operation and can cause music playback interruptions for large iterators."; diff --git a/src/main.rs b/src/main.rs index 2013436..b160f60 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -//! A language all about interation to play your music files. +//! A language all about iteration to play your music files. //! This project implements the interpreter (mps-interpreter), music player (mps-player), and CLI interface for MPS (root). //! The CLI interface includes a REPL for running scripts. //! The REPL interactive mode also provides more details about using MPS through the `?help` command. @@ -22,7 +22,7 @@ //! **I thought it would be fun**. I also wanted to be able to play my music without having to be at the whim of someone else's algorithm (and music), and playing just by album or artist was getting boring. I also thought designing a language specifically for iteration would be a novel approach to a language (though every approach is a novel approach for me). //! //! ## What is MPS? -//! **Music Playlist Script (MPS) is technically a query language for music files.** It uses an (auto-generated) SQLite3 database for SQL queries and can also directly query the filesystem. Queries can be filtered and extended by using filters and functions built-in to MPS (see mps-interpreter's README.md). +//! **Music Playlist Script (MPS) is technically a query language for music files.** It uses an (auto-generated) SQLite3 database for SQL queries and can also directly query the filesystem. Queries can be modified by using filters, functions, and sorters built-in to MPS (see mps-interpreter's README.md). //! //! ## Is MPS a scripting language? //! **No**. Technically, it was designed to be one, but it doesn't meet the requirements of a scripting language (yet). One day, I would like it be Turing-complete and then it could be considered a scripting language. At the moment it is barely a query language. diff --git a/src/repl.rs b/src/repl.rs index 6a02334..821cc53 100644 --- a/src/repl.rs +++ b/src/repl.rs @@ -159,6 +159,7 @@ fn repl_commands(command_str: &str) { "?help" => println!("{}", super::help::HELP_STRING), "?function" | "?functions" => println!("{}", super::help::FUNCTIONS), "?filter" | "?filters" => println!("{}", super::help::FILTERS), + "?sort" | "?sorter" | "?sorters" => println!("{}", super::help::SORTERS), _ => println!("Unknown command, try ?help"), } }