From 67073417c345cc7399808ffec03a7e34eb350b91 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Sat, 10 Nov 2018 04:52:09 -0500 Subject: add a command to recommend things to listen to --- src/db.rs | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) (limited to 'src/db.rs') diff --git a/src/db.rs b/src/db.rs index efc1a88..63caa87 100644 --- a/src/db.rs +++ b/src/db.rs @@ -23,6 +23,15 @@ const SCHEMA: &'static str = " WHERE strftime('%s') - timestamp < 60*60*24*7; "; +#[derive(Eq, PartialEq, Copy, Clone)] +pub enum TimeWindow { + All, + Yearly, + Monthly, + Weekly, + None, +} + pub struct DB { conn: rusqlite::Connection, } @@ -128,4 +137,111 @@ impl DB { errs.map(|_| cols) } + + pub fn recommend_artists( + &self, + count: u64, + random: bool, + include: TimeWindow, + exclude: TimeWindow, + ) -> failure::Fallible> { + let exclude = if exclude != TimeWindow::None { + format!(" + WHERE artist NOT IN ( + SELECT DISTINCT(artist) + FROM {} + ) + ", timewindow_table(&exclude)) + } + else { + "".to_string() + }; + let order = if random { + "ORDER BY random()" + } + else { + "ORDER BY count(artist) * (strftime('%s') - max(timestamp)) DESC" + }; + + let sql = format!(" + SELECT artist + FROM {} + {} + GROUP BY artist + {} + LIMIT {} + ", timewindow_table(&include), exclude, order, count); + let mut sth = self.conn.prepare(&sql)?; + let artists = sth.query_and_then(rusqlite::NO_PARAMS, |row| { + Ok(row.get_checked(0)?) + })?.collect::>>()?; + + Ok(artists) + } + + pub fn recommend_album( + &self, + artist: &str, + random: bool, + include: TimeWindow, + exclude: TimeWindow, + ) -> failure::Fallible { + let mut params = vec![artist]; + let exclude = if exclude != TimeWindow::None { + params.push(artist); + format!(" + AND album NOT IN ( + SELECT DISTINCT(album) + FROM {} + WHERE artist = ? + ) + ", timewindow_table(&exclude)) + } + else { + "".to_string() + }; + let order = if random { + "ORDER BY random()" + } + else { + "ORDER BY count(album) * (strftime('%s') - max(timestamp)) DESC" + }; + + let sql = format!(" + SELECT album + FROM {} + WHERE artist = ? + {} + GROUP BY album + {} + LIMIT 1 + ", timewindow_table(&include), exclude, order); + let mut sth = self.conn.prepare(&sql)?; + let artists = sth.query_row::, _, _>(¶ms, |row| { + Ok(row.get_checked(0)?) + })??; + + Ok(artists) + } +} + +pub fn parse_timewindow(s: &str) -> TimeWindow { + match s { + "all" => TimeWindow::All, + "yearly" => TimeWindow::Yearly, + "monthly" => TimeWindow::Monthly, + "weekly" => TimeWindow::Weekly, + "none" => TimeWindow::None, + _ => unreachable!(), + } +} + +fn timewindow_table(tw: &TimeWindow) -> String { + match tw { + TimeWindow::All => "tracks".to_string(), + TimeWindow::Yearly => "yearly_tracks".to_string(), + TimeWindow::Monthly => "monthly_tracks".to_string(), + TimeWindow::Weekly => "weekly_tracks".to_string(), + _ => unreachable!(), + } } -- cgit v1.2.3-54-g00ecf