Rename to MuSS

This commit is contained in:
NGnius (Graham) 2022-07-01 17:33:37 -04:00
parent a64da47cd0
commit 3a4dce084e
19 changed files with 98 additions and 96 deletions

16
Cargo.lock generated
View file

@ -1229,17 +1229,17 @@ dependencies = [
] ]
[[package]] [[package]]
name = "mps" name = "muss"
version = "0.8.0" version = "0.8.0"
dependencies = [ dependencies = [
"clap 3.2.8", "clap 3.2.8",
"console", "console",
"mps-interpreter", "muss-interpreter",
"mps-player", "muss-player",
] ]
[[package]] [[package]]
name = "mps-interpreter" name = "muss-interpreter"
version = "0.8.0" version = "0.8.0"
dependencies = [ dependencies = [
"bliss-audio-symphonia", "bliss-audio-symphonia",
@ -1255,23 +1255,23 @@ dependencies = [
] ]
[[package]] [[package]]
name = "mps-m3u8" name = "muss-m3u8"
version = "0.8.0" version = "0.8.0"
dependencies = [ dependencies = [
"clap 3.2.8", "clap 3.2.8",
"m3u8-rs", "m3u8-rs",
"mps-interpreter", "muss-interpreter",
] ]
[[package]] [[package]]
name = "mps-player" name = "muss-player"
version = "0.8.0" version = "0.8.0"
dependencies = [ dependencies = [
"fluent-uri", "fluent-uri",
"m3u8-rs", "m3u8-rs",
"mpd", "mpd",
"mpris-player", "mpris-player",
"mps-interpreter", "muss-interpreter",
"rodio", "rodio",
] ]

View file

@ -1,9 +1,9 @@
[package] [package]
name = "mps" name = "muss"
version = "0.8.0" version = "0.8.0"
edition = "2021" edition = "2021"
authors = ["NGnius (Graham) <ngniusness@gmail.com>"] authors = ["NGnius (Graham) <ngniusness@gmail.com>"]
description = "Music Playlist Script language (MPS)" description = "Music Set Script language (MuSS)"
license = "LGPL-2.1-only OR GPL-3.0-only" license = "LGPL-2.1-only OR GPL-3.0-only"
repository = "https://github.com/NGnius/mps" repository = "https://github.com/NGnius/mps"
keywords = ["audio", "playlist", "scripting", "language"] keywords = ["audio", "playlist", "scripting", "language"]
@ -19,17 +19,17 @@ members = [
[dependencies] [dependencies]
# local # local
mps-interpreter = { version = "0.8.0", path = "./interpreter" } muss-interpreter = { version = "0.8.0", path = "./interpreter" }
# external # external
clap = { version = "3.0", features = ["derive"] } clap = { version = "3.0", features = ["derive"] }
console = { version = "0.15" } console = { version = "0.15" }
[target.'cfg(not(target_os = "linux"))'.dependencies] [target.'cfg(not(target_os = "linux"))'.dependencies]
mps-player = { version = "0.8.0", path = "./player", default-features = false } muss-player = { version = "0.8.0", path = "./player", default-features = false }
[target.'cfg(target_os = "linux")'.dependencies] [target.'cfg(target_os = "linux")'.dependencies]
# TODO fix need to specify OS-specific dependency of mps-player # TODO fix need to specify OS-specific dependency of mps-player
mps-player = { version = "0.8.0", path = "./player", features = ["mpris-player", "mpd"] } muss-player = { version = "0.8.0", path = "./player", features = ["mpris-player", "mpd"] }
[profile.release] [profile.release]
debug = false debug = false

View file

@ -1,11 +1,11 @@
# mps # muss
![repl_demo](https://raw.githubusercontent.com/NGnius/mps/master/extras/demo.png) ![repl_demo](https://raw.githubusercontent.com/NGnius/mps/master/extras/demo.png)
Sort, filter and analyse your music to create great playlists. Sort, filter and analyse your music to create great playlists.
This project implements the interpreter (mps-interpreter), music player (mps-player), and CLI interface for MPS (root). This project implements the interpreter (`./interpreter`), music player (`./player`), and CLI interface for Muss (`./`).
The CLI interface includes a REPL for running scripts. The CLI interface includes a REPL for running scripts.
The REPL interactive mode also provides more details about using MPS through the `?help` command. The REPL interactive mode also provides more details about using Muss through the `?help` command.
## Usage ## Usage
To access the REPL, simply run `cargo run`. You will need the [Rust toolchain installed](https://rustup.rs/). For a bit of extra performance, run `cargo run --release` instead. To access the REPL, simply run `cargo run`. You will need the [Rust toolchain installed](https://rustup.rs/). For a bit of extra performance, run `cargo run --release` instead.
@ -15,38 +15,38 @@ To access the REPL, simply run `cargo run`. You will need the [Rust toolchain in
### One-liners ### One-liners
All songs by artist `<artist>` (in your library), sorted by similarity to a random first song by the artist. All songs by artist `<artist>` (in your library), sorted by similarity to a random first song by the artist.
```mps ```muss
files().(artist? like "<artist>")~(shuffle)~(advanced bliss_next); files().(artist? like "<artist>")~(shuffle)~(advanced bliss_next);
``` ```
All songs with a `.flac` file extension (anywhere in their path -- not necessarily at the end). All songs with a `.flac` file extension (anywhere in their path -- not necessarily at the end).
```mps ```muss
files().(filename? like ".flac"); files().(filename? like ".flac");
``` ```
All songs by artist `<artist1>` or `<artist2>`, sorted by similarity to a random first song by either artist. All songs by artist `<artist1>` or `<artist2>`, sorted by similarity to a random first song by either artist.
```mps ```muss
files().(artist? like "<artist1>" || artist? like "<artist2>")~(shuffle)~(advanced bliss_next); files().(artist? like "<artist1>" || artist? like "<artist2>")~(shuffle)~(advanced bliss_next);
``` ```
### Bigger examples ### Bigger examples
For now, check out `./src/tests`, `./mps-player/tests`, and `./mps-interpreter/tests` for examples. For now, check out `./src/tests`, `./player/tests`, and `./interpreter/tests` for examples.
One day I'll add pretty REPL example pictures and some script files... One day I'll add pretty REPL example pictures and some script files...
// TODO // TODO
## FAQ ## FAQ
### Can I use MPS right now? ### Can I use Muss right now?
**Sure!** It's never complete, but MPS is completely useable right now. Hopefully most of the bugs have been ironed out as well :) **Sure!** It's never complete, but Muss is completely useable right now. Hopefully most of the bugs have been ironed out as well :)
### Why write a new language? ### Why write a new language?
**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. Designing a language specifically for iteration seemed like a cool & novel way of doing it, too (though every approach is a novel approach for me). **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. Designing a language specifically for iteration seemed like a cool & novel way of doing it, too (though every approach is a novel approach for me).
### What is MPS? ### What is Muss?
**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). **Music Set Script (MuSS) is a language for describing a playlist of music.** 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 Muss (see interpreter's README.md).
### Is MPS a scripting language? ### Is Muss a scripting language?
**Yes**. It evolved from a simple query language into something that can do arbitrary calculations. Whether it's Turing-complete is still unproven, but it's powerful enough for what I want it to do. **Yes**. It evolved from a simple query language into something that can do arbitrary calculations. Whether it's Turing-complete is still unproven, but it's powerful enough for what I want it to do.

View file

@ -1,5 +1,5 @@
[package] [package]
name = "mps-interpreter" name = "muss-interpreter"
version = "0.8.0" version = "0.8.0"
edition = "2021" edition = "2021"
license = "LGPL-2.1-only OR GPL-3.0-only" license = "LGPL-2.1-only OR GPL-3.0-only"

View file

@ -1,21 +1,21 @@
# mps-interpreter # muss-interpreter
All necessary components to interpret and run a MPS script. All necessary components to interpret and run a Muss script.
MpsFaye is the new interpreter, which replaces the old MpsInterpretor and MpsRunner types. Interpreter is the Muss script interpreter.
MpsDebugger can be used to run scripts with a custom debug harness. Debugger can be used to run scripts within a custom debug harness.
Since MPS is centered around iterators, script execution is also done by iterating. Since Muss is centered around iterators, script execution is also done by iterating.
```rust ```rust
use std::io::Cursor; use std::io::Cursor;
use mps_interpreter::*; use muss_interpreter::*;
let cursor = Cursor::new( let cursor = Cursor::new(
"files(folder=`~/Music/`, recursive=true)" // retrieve all files from Music folder "files(folder=`~/Music/`, recursive=true)" // retrieve all files from Music folder
); );
let interpreter = MpsFaye::with_stream(cursor); let interpreter = Interpreter::with_stream(cursor);
// warning: my library has ~3800 songs, so this outputs too much information to be useful. // warning: my library has ~3800 songs, so this outputs too much information to be useful.
for result in interpreter { for result in interpreter {
@ -28,15 +28,15 @@ for result in interpreter {
## Standard Vocabulary ## Standard Vocabulary
By default, the standard vocabulary is used to parse the stream when iterating the interpreter. By default, the standard vocabulary is used to parse the stream when iterating the interpreter.
The standard vocabulary defines the valid statement syntax for MPS and parses syntax into special Rust Iterators which can be used to execute the statement. The standard vocabulary defines the valid statement syntax for Muss and parses syntax into special Rust Iterators which can be used to execute the statement.
To declare your own vocabulary, use MpsRunner::with_settings to provide a MpsInterpretor with a custom vocabulary (I'm not sure why you would, but I'm not going to stop you). To declare your own vocabulary, use Interpretor::with or Interpreter::with_vocab with a custom vocabulary (I'm not sure why you would, but I'm not going to stop you).
### Oddities ### Oddities
The MPS standard syntax does a few things that most other languages don't, because I wanted it to. The Muss standard syntax does a few things that most other languages don't, because I wanted it to.
\` can be used in place of " -- To make it easier to write SQL, string literals may be surrounded by backticks instead of quotation marks. \` can be used in place of " -- To make it easier to write SQL, string literals may be surrounded by backticks instead of quotation marks.
; -- The REPL will automatically place semicolons when Enter is pressed and it's not inside of brackets or a literal. MPS requires semicolons at the end of every statement, though, so MPS files must use semicolons. ; -- The REPL will automatically place semicolons when Enter is pressed and it's not inside of brackets or a literal. Muss requires semicolons at the end of every statement, though, so Muss files must use semicolons.
### Filters ### Filters
Operations to reduce the items in an iterable: `iterable.(filter);`. Operations to reduce the items in an iterable: `iterable.(filter);`.
@ -47,6 +47,8 @@ E.g. `files(folder="~/Music/", recursive=true).(title == "Romantic Traffic");` i
#### field like something #### field like something
#### field unlike something
#### field matches some_regex #### field matches some_regex
#### field != something #### field != something
@ -59,7 +61,7 @@ E.g. `files(folder="~/Music/", recursive=true).(title == "Romantic Traffic");` i
#### field < something -- e.g. `iterable.(title == "Romantic Traffic");` #### 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 Item 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);` #### start..end -- e.g. `iterable.(0..42);`
@ -109,7 +111,7 @@ Initialize the SQLite database connection using the provided parameters. This mu
#### sql("SQL query here"); #### sql("SQL query here");
Perform a raw SQLite query on the database which MPS auto-generates. An iterator of the results is returned. Perform a raw SQLite query on the database which Muss auto-generates. An iterator of the results is returned.
#### song("something"); #### song("something");
@ -168,7 +170,7 @@ Operations to sort the items in an iterable: `iterable~(sorter)` OR `iterable.so
#### field -- e.g. `iterable~(filename);` #### 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. Sort by a Item field. Valid field names change depending on what information is available when the Item 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.
#### shuffle #### shuffle
#### random shuffle -- e.g. `iterable~(shuffle);` #### random shuffle -- e.g. `iterable~(shuffle);`
@ -201,7 +203,7 @@ Assign something to the variable. The variable must have already been declared.
The empty or null constant. The empty or null constant.
#### if condition { something } else { something_else } -- e.g. #### if condition { something } else { something_else } -- e.g.
```mps ```muss
if item.title == `Romantic Traffic` { if item.title == `Romantic Traffic` {
} else { } else {

View file

@ -1,19 +1,19 @@
//! All necessary components to interpret and run a MPS script. //! All necessary components to interpret and run a Muss script.
//! //!
//! MpsFaye is the new interpreter, which replaces the old MpsInterpretor and MpsRunner types. //! Interpreter is the Muss script interpreter.
//! MpsDebugger can be used to run scripts with a custom debug harness. //! Debugger can be used to run scripts within a custom debug harness.
//! Since MPS is centered around iterators, script execution is also done by iterating. //! Since Muss is centered around iterators, script execution is also done by iterating.
//! //!
//! //!
//! ``` //! ```
//! use std::io::Cursor; //! use std::io::Cursor;
//! use mps_interpreter::*; //! use muss_interpreter::*;
//! //!
//! let cursor = Cursor::new( //! let cursor = Cursor::new(
//! "files(folder=`~/Music/`, recursive=true)" // retrieve all files from Music folder //! "files(folder=`~/Music/`, recursive=true)" // retrieve all files from Music folder
//! ); //! );
//! //!
//! let interpreter = MpsFaye::with_stream(cursor); //! let interpreter = Interpreter::with_stream(cursor);
//! //!
//! // warning: my library has ~3800 songs, so this outputs too much information to be useful. //! // warning: my library has ~3800 songs, so this outputs too much information to be useful.
//! for result in interpreter { //! for result in interpreter {
@ -26,15 +26,15 @@
//! //!
//! # Standard Vocabulary //! # Standard Vocabulary
//! By default, the standard vocabulary is used to parse the stream when iterating the interpreter. //! By default, the standard vocabulary is used to parse the stream when iterating the interpreter.
//! The standard vocabulary defines the valid statement syntax for MPS and parses syntax into special Rust Iterators which can be used to execute the statement. //! The standard vocabulary defines the valid statement syntax for Muss and parses syntax into special Rust Iterators which can be used to execute the statement.
//! To declare your own vocabulary, use MpsRunner::with_settings to provide a MpsInterpretor with a custom vocabulary (I'm not sure why you would, but I'm not going to stop you). //! To declare your own vocabulary, use Interpretor::with or Interpreter::with_vocab with a custom vocabulary (I'm not sure why you would, but I'm not going to stop you).
//! //!
//! ## Oddities //! ## Oddities
//! The MPS standard syntax does a few things that most other languages don't, because I wanted it to. //! The Muss standard syntax does a few things that most other languages don't, because I wanted it to.
//! //!
//! \` can be used in place of " -- To make it easier to write SQL, string literals may be surrounded by backticks instead of quotation marks. //! \` can be used in place of " -- To make it easier to write SQL, string literals may be surrounded by backticks instead of quotation marks.
//! //!
//! ; -- The REPL will automatically place semicolons when Enter is pressed and it's not inside of brackets or a literal. MPS requires semicolons at the end of every statement, though, so MPS files must use semicolons. //! ; -- The REPL will automatically place semicolons when Enter is pressed and it's not inside of brackets or a literal. Muss requires semicolons at the end of every statement, though, so Muss files must use semicolons.
//! //!
//! ## Filters //! ## Filters
//! Operations to reduce the items in an iterable: `iterable.(filter);`. //! Operations to reduce the items in an iterable: `iterable.(filter);`.
@ -59,7 +59,7 @@
//! //!
//! ### field < something -- e.g. `iterable.(title == "Romantic Traffic");` //! ### 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 Item 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);` //! ### start..end -- e.g. `iterable.(0..42);`
@ -109,7 +109,7 @@
//! //!
//! ### sql("SQL query here"); //! ### sql("SQL query here");
//! //!
//! Perform a raw SQLite query on the database which MPS auto-generates. An iterator of the results is returned. //! Perform a raw SQLite query on the database which Muss auto-generates. An iterator of the results is returned.
//! //!
//! ### song("something"); //! ### song("something");
//! //!
@ -168,7 +168,7 @@
//! //!
//! ### field -- e.g. `iterable~(filename);` //! ### 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. //! Sort by a Item field. Valid field names change depending on what information is available when the Item 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.
//! //!
//! ### shuffle //! ### shuffle
//! ### random shuffle -- e.g. `iterable~(shuffle);` //! ### random shuffle -- e.g. `iterable~(shuffle);`
@ -201,7 +201,7 @@
//! The empty or null constant. //! The empty or null constant.
//! //!
//! ### if condition { something } else { something_else } -- e.g. //! ### if condition { something } else { something_else } -- e.g.
//! ```mps //! ```muss
//! if item.title == `Romantic Traffic` { //! if item.title == `Romantic Traffic` {
//! //!
//! } else { //! } else {

View file

@ -1,5 +1,5 @@
[package] [package]
name = "mps-m3u8" name = "muss-m3u8"
version = "0.8.0" version = "0.8.0"
edition = "2021" edition = "2021"
authors = ["NGnius <ngniusness@gmail.com>"] authors = ["NGnius <ngniusness@gmail.com>"]
@ -13,7 +13,7 @@ readme = "README.md"
[dependencies] [dependencies]
# local # local
mps-interpreter = { version = "0.8.0", path = "../interpreter" } muss-interpreter = { version = "0.8.0", path = "../interpreter" }
# external # external
clap = { version = "3.0", features = ["derive"] } clap = { version = "3.0", features = ["derive"] }
m3u8-rs = { version = "^3.0.0" } m3u8-rs = { version = "^3.0.0" }

View file

@ -1,6 +1,6 @@
//! Minimal CLI tool to generate a m3u8 playlist from a MPS file. //! Minimal CLI tool to generate a m3u8 playlist from a Muss script.
//! This does not support playback, so it can run on any platform with a filesystem. //! This does not support playback, so it can run on any platform with a filesystem.
//! Use `mps-m3u8 --help` for usage instructions. //! Use `muss-m3u8 --help` for usage instructions.
//! //!
mod cli; mod cli;

View file

@ -1,5 +1,5 @@
[package] [package]
name = "mps-player" name = "muss-player"
version = "0.8.0" version = "0.8.0"
edition = "2021" edition = "2021"
license = "LGPL-2.1-only OR GPL-3.0-only" license = "LGPL-2.1-only OR GPL-3.0-only"
@ -12,7 +12,7 @@ fluent-uri = { version = "^0.1" }
mpd = { version = "0.0.12", optional = true } mpd = { version = "0.0.12", optional = true }
# local # local
mps-interpreter = { path = "../interpreter", version = "0.8.0" } muss-interpreter = { path = "../interpreter", version = "0.8.0" }
[target.'cfg(target_os = "linux")'.dependencies] [target.'cfg(target_os = "linux")'.dependencies]
#dbus = { version = "^0.9" } #dbus = { version = "^0.9" }

View file

@ -1,8 +1,8 @@
# mps-player # muss-player
An MPS playback library with support for media controls (Linux & D-Bus only atm). A Muss playback library with support for media controls (Linux & D-Bus only atm).
This handles the output from interpreting a script. This handles the output from interpreting a script.
Music playback and m3u8 playlist generation are implemented in this part of the project. Music playback and m3u8 playlist generation are implemented in this part of the project.
License: LGPL-2.1-only OR GPL-2.0-or-later License: LGPL-2.1-only OR GPL-3.0-only

View file

@ -1,7 +1,7 @@
use std::sync::mpsc::{channel, Receiver, Sender}; use std::sync::mpsc::{channel, Receiver, Sender};
use std::thread::JoinHandle; use std::thread::JoinHandle;
use mps_interpreter::tokens::TokenReader; use muss_interpreter::tokens::TokenReader;
use super::os_controls::SystemControlWrapper; use super::os_controls::SystemControlWrapper;
use super::player_wrapper::{ControlAction, PlayerServer, PlayerAction}; use super::player_wrapper::{ControlAction, PlayerServer, PlayerAction};

View file

@ -1,4 +1,4 @@
//! An playback library with support for media controls (Linux & D-Bus only atm). //! A Muss playback library with support for media controls (Linux & D-Bus only atm).
//! This handles the output from interpreting a script. //! This handles the output from interpreting a script.
//! Music playback and m3u8 playlist generation are implemented in this part of the project. //! Music playback and m3u8 playlist generation are implemented in this part of the project.
//! //!

View file

@ -7,7 +7,7 @@ use std::thread::JoinHandle;
use mpris_player::{Metadata, MprisPlayer, PlaybackStatus}; use mpris_player::{Metadata, MprisPlayer, PlaybackStatus};
#[cfg(all(target_os = "linux", feature = "os-controls", feature = "mpris-player"))] #[cfg(all(target_os = "linux", feature = "os-controls", feature = "mpris-player"))]
use mps_interpreter::Item; use muss_interpreter::Item;
//use super::Controller; //use super::Controller;
use super::player_wrapper::{ControlAction, PlaybackAction}; use super::player_wrapper::{ControlAction, PlaybackAction};

View file

@ -10,7 +10,7 @@ use mpd::{Client, Song, error};
use super::uri::Uri; use super::uri::Uri;
use mps_interpreter::{tokens::TokenReader, Interpreter, Item}; use muss_interpreter::{tokens::TokenReader, Interpreter, Item};
//use super::PlaybackError; //use super::PlaybackError;
use super::PlayerError; use super::PlayerError;

View file

@ -1,8 +1,8 @@
use std::sync::mpsc::{Receiver, Sender}; use std::sync::mpsc::{Receiver, Sender};
use std::{thread, thread::JoinHandle}; use std::{thread, thread::JoinHandle};
use mps_interpreter::tokens::TokenReader; use muss_interpreter::tokens::TokenReader;
use mps_interpreter::Item; use muss_interpreter::Item;
use super::Player; use super::Player;
use super::PlayerError; use super::PlayerError;

View file

@ -2,7 +2,7 @@ use std::path::Path;
use std::io; use std::io;
use std::fs; use std::fs;
use mps_interpreter::{Intrepreter, tokens::TokenReader}; use muss_interpreter::{Intrepreter, tokens::TokenReader};
use super::{Player, PlaybackError}; use super::{Player, PlaybackError};

View file

@ -1,4 +1,4 @@
/// Standard help string containing usage information for MPS. /// Standard help string containing usage information for Muss.
pub const HELP_STRING: &str = 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. "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.
@ -13,7 +13,7 @@ These always return an iterable which can be manipulated.
Initialize the SQLite database connection using the provided parameters. This must be performed before any other database operation (otherwise the database will already be connected with default settings). Returns an empty iterable. Initialize the SQLite database connection using the provided parameters. This must be performed before any other database operation (otherwise the database will already be connected with default settings). Returns an empty iterable.
sql(`SQL query here`) sql(`SQL query here`)
Perform a raw SQLite query on the database which MPS auto-generates. An iterator of the results is returned. Perform a raw SQLite query on the database which Muss auto-generates. An iterator of the results is returned.
song(`something`) song(`something`)
Retrieve all songs in the database with a title like something. Retrieve all songs in the database with a title like something.
@ -68,7 +68,7 @@ Operations to reduce the items in an iterable: iterable.(filter)
field > something field > something
field <= something field <= something
field < something -- e.g. iterable.(title == `Romantic Traffic`) field < something -- e.g. iterable.(title == `Romantic Traffic`)
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). Compare all items, keeping only those that match the condition. Valid field names change depending on what information is available when the Item 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) 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. 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.
@ -100,17 +100,17 @@ pub const SORTERS: &str =
Operations to sort the items in an iterable: iterable~(sorter) OR iterable.sort(sorter) Operations to sort the items in an iterable: iterable~(sorter) OR iterable.sort(sorter)
field -- e.g. iterable~(filename) 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. Sort by a Item field. Valid field names change depending on what information is available when the Item 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.
shuffle shuffle
random shuffle -- e.g. iterable~(shuffle) random shuffle -- e.g. iterable~(shuffle)
Shuffle the songs in the iterator. This is random for up to 2^16 items, and then the randomness degrades (but at that point you won't notice). Shuffle the songs in the iterator. This is random for up to 2^16 items, and then the randomness degrades (but at that point you won't notice).
advanced bliss_first -- e.g. iterable~(advanced bliss_first) advanced bliss_first -- e.g. iterable~(advanced bliss_first)
Sort by the distance (similarity) from the first song in the iterator. 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. Requires `advanced` mps-interpreter feature. Sort by the distance (similarity) from the first song in the iterator. 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. Requires `advanced` interpreter feature.
advanced bliss_next -- e.g. iterable~(advanced bliss_next) advanced bliss_next -- e.g. iterable~(advanced bliss_next)
Sort by the distance (similarity) between the last played song in the iterator. Similar to bliss_first. 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. Requires `advanced` mps-interpreter feature."; Sort by the distance (similarity) between the last played song in the iterator. Similar to bliss_first. 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. Requires `advanced` interpreter feature.";
pub const PROCEDURES: &str = pub const PROCEDURES: &str =
"PROCEDURES (?procedures) "PROCEDURES (?procedures)

View file

@ -1,7 +1,7 @@
//! Sort, filter and analyse your music to create great playlists. //! Sort, filter and analyse your music to create great playlists.
//! This project implements the interpreter (mps-interpreter), music player (mps-player), and CLI interface for MPS (root). //! This project implements the interpreter (`./interpreter`), music player (`./player`), and CLI interface for Muss (`./`).
//! The CLI interface includes a REPL for running scripts. //! The CLI interface includes a REPL for running scripts.
//! The REPL interactive mode also provides more details about using MPS through the `?help` command. //! The REPL interactive mode also provides more details about using Muss through the `?help` command.
//! //!
//! # Usage //! # Usage
//! To access the REPL, simply run `cargo run`. You will need the [Rust toolchain installed](https://rustup.rs/). For a bit of extra performance, run `cargo run --release` instead. //! To access the REPL, simply run `cargo run`. You will need the [Rust toolchain installed](https://rustup.rs/). For a bit of extra performance, run `cargo run --release` instead.
@ -11,38 +11,38 @@
//! ## One-liners //! ## One-liners
//! //!
//! All songs by artist `<artist>` (in your library), sorted by similarity to a random first song by the artist. //! All songs by artist `<artist>` (in your library), sorted by similarity to a random first song by the artist.
//! ```mps //! ```muss
//! files().(artist? like "<artist>")~(shuffle)~(advanced bliss_next); //! files().(artist? like "<artist>")~(shuffle)~(advanced bliss_next);
//! ``` //! ```
//! //!
//! All songs with a `.flac` file extension (anywhere in their path -- not necessarily at the end). //! All songs with a `.flac` file extension (anywhere in their path -- not necessarily at the end).
//! ```mps //! ```muss
//! files().(filename? like ".flac"); //! files().(filename? like ".flac");
//! ``` //! ```
//! //!
//! All songs by artist `<artist1>` or `<artist2>`, sorted by similarity to a random first song by either artist. //! All songs by artist `<artist1>` or `<artist2>`, sorted by similarity to a random first song by either artist.
//! ```mps //! ```muss
//! files().(artist? like "<artist1>" || artist? like "<artist2>")~(shuffle)~(advanced bliss_next); //! files().(artist? like "<artist1>" || artist? like "<artist2>")~(shuffle)~(advanced bliss_next);
//! ``` //! ```
//! //!
//! ## Bigger examples //! ## Bigger examples
//! //!
//! For now, check out `./src/tests`, `./mps-player/tests`, and `./mps-interpreter/tests` for examples. //! For now, check out `./src/tests`, `./player/tests`, and `./interpreter/tests` for examples.
//! One day I'll add pretty REPL example pictures and some script files... //! One day I'll add pretty REPL example pictures and some script files...
//! // TODO //! // TODO
//! //!
//! # FAQ //! # FAQ
//! //!
//! ## Can I use MPS right now? //! ## Can I use Muss right now?
//! **Sure!** It's never complete, but MPS is completely useable right now. Hopefully most of the bugs have been ironed out as well :) //! **Sure!** It's never complete, but Muss is completely useable right now. Hopefully most of the bugs have been ironed out as well :)
//! //!
//! ## Why write a new language? //! ## Why write a new language?
//! **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. Designing a language specifically for iteration seemed like a cool & novel way of doing it, too (though every approach is a novel approach for me). //! **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. Designing a language specifically for iteration seemed like a cool & novel way of doing it, too (though every approach is a novel approach for me).
//! //!
//! ## What is MPS? //! ## What is Muss?
//! **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). //! **Music Set Script (MuSS) is a language for describing a playlist of music.** 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 Muss (see interpreter's README.md).
//! //!
//! ## Is MPS a scripting language? //! ## Is Muss a scripting language?
//! **Yes**. It evolved from a simple query language into something that can do arbitrary calculations. Whether it's Turing-complete is still unproven, but it's powerful enough for what I want it to do. //! **Yes**. It evolved from a simple query language into something that can do arbitrary calculations. Whether it's Turing-complete is still unproven, but it's powerful enough for what I want it to do.
//! //!
@ -54,8 +54,8 @@ mod repl;
use std::io; use std::io;
use std::path::PathBuf; use std::path::PathBuf;
use mps_interpreter::Interpreter; use muss_interpreter::Interpreter;
use mps_player::{Controller, Player, PlayerError}; use muss_player::{Controller, Player, PlayerError};
#[allow(dead_code)] #[allow(dead_code)]
fn play_cursor() -> Result<(), PlayerError> { fn play_cursor() -> Result<(), PlayerError> {
@ -81,7 +81,7 @@ fn main() {
// build playback controller // build playback controller
let script_file2 = script_file.clone(); let script_file2 = script_file.clone();
let volume = args.volume.clone(); let volume = args.volume.clone();
let mpd = match args.mpd.clone().map(|a| mps_player::mpd_connection(a.parse().unwrap())).transpose() { let mpd = match args.mpd.clone().map(|a| muss_player::mpd_connection(a.parse().unwrap())).transpose() {
Ok(mpd) => mpd, Ok(mpd) => mpd,
Err(e) => panic!("Abort: Cannot connect to MPD: {}", e), Err(e) => panic!("Abort: Cannot connect to MPD: {}", e),
}; };
@ -125,7 +125,7 @@ fn main() {
} }
} else { } else {
// start REPL // start REPL
println!("Welcome to MPS interactive mode!"); println!("Welcome to Muss interactive mode!");
println!("Run ?help for usage instructions."); println!("Run ?help for usage instructions.");
//println!("End a statement with ; to execute it."); //println!("End a statement with ; to execute it.");
repl::repl(args) repl::repl(args)

View file

@ -4,8 +4,8 @@ use std::io::{self, Write};
use console::{Key, Term}; use console::{Key, Term};
use mps_interpreter::Interpreter; use muss_interpreter::Interpreter;
use mps_player::{Controller, Player}; use muss_player::{Controller, Player};
use super::channel_io::{channel_io, ChannelWriter}; use super::channel_io::{channel_io, ChannelWriter};
use super::cli::CliArgs; use super::cli::CliArgs;
@ -47,7 +47,7 @@ pub fn repl(args: CliArgs) {
term.set_title("mps"); term.set_title("mps");
let (writer, reader) = channel_io(); let (writer, reader) = channel_io();
let volume = args.volume.clone(); let volume = args.volume.clone();
let mpd = match args.mpd.clone().map(|a| mps_player::mpd_connection(a.parse().unwrap())).transpose() { let mpd = match args.mpd.clone().map(|a| muss_player::mpd_connection(a.parse().unwrap())).transpose() {
Ok(mpd) => mpd, Ok(mpd) => mpd,
Err(e) => { Err(e) => {
eprintln!("Cannot connect to MPD address `{}`: {}", args.mpd.unwrap(), e); eprintln!("Cannot connect to MPD address `{}`: {}", args.mpd.unwrap(), e);
@ -458,7 +458,7 @@ fn display_history_line(state: &mut ReplState, args: &CliArgs) {
} }
#[inline(always)] #[inline(always)]
fn error_prompt(error: mps_player::PlayerError, args: &CliArgs) { fn error_prompt(error: muss_player::PlayerError, args: &CliArgs) {
eprintln!("E{}{}", args.prompt, error); eprintln!("E{}{}", args.prompt, error);
} }