Skip to content

Commit

Permalink
Make legend artists case-insensitive
Browse files Browse the repository at this point in the history
Move to ES classes for backbone extending, which found some type errors.

Fix a type error (array.size() does not exist) in num_requests_pending.
  • Loading branch information
mhansen committed Jan 1, 2025
1 parent 440f67a commit 69e2b8e
Show file tree
Hide file tree
Showing 30 changed files with 250 additions and 169 deletions.
10 changes: 5 additions & 5 deletions public/AppController.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
let appModel = new AppModel;
let fetchModel = new FetchModel;
let graphViewModel = new FlotScrobbleGraphViewModel;
let legendModel = new LegendModel;
let scrobbleCollection = new ScrobbleCollection;
let appModel = new AppModel();
let fetchModel = new FetchModel();
let graphViewModel = new FlotScrobbleGraphViewModel();
let legendModel = new LegendModel();
let scrobbleCollection = new ScrobbleCollection();
let requestQueue = new RequestQueue({
max_n_reqs_in_progress: 4
});
Expand Down
14 changes: 9 additions & 5 deletions public/models/AppModel.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
// Global state that I couldn't find a more specific place for
// It's all used to form the path of the URL.
const AppModel = Backbone.Model.extend({
user() { return this.get("user"); },
class AppModel extends Backbone.Model {
user() {
return this.get("user");
}
initialize() {
this.set({ user: null });
this.set({ filterTerm: "" });
},
filterRegex() { return new RegExp(this.get("filterTerm"), "i"); },
}
filterRegex() {
return new RegExp(this.get("filterTerm"), "i");
}
validate(attrs) {
try {
new RegExp(attrs.filterTerm, "i");
Expand All @@ -16,4 +20,4 @@ const AppModel = Backbone.Model.extend({
return `Whoops! That's not a regular expression: ${error}`;
}
}
});
}
8 changes: 4 additions & 4 deletions public/models/FetchModel.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
const FetchModel = Backbone.Model.extend({
class FetchModel extends Backbone.Model {
initialize() {
this.set({
pagesFetched: [],
totalPages: 0,
lastPageFetched: 0,
isFetching: false
});
},
numPagesFetched() { return this.get("pagesFetched").length; },
}
numPagesFetched() { return this.get("pagesFetched").length; }
fetch_scrobbles(username) {
if (!username) {
throw "Invalid Username";
Expand Down Expand Up @@ -65,4 +65,4 @@ const FetchModel = Backbone.Model.extend({
})();
});
}
});
}
20 changes: 13 additions & 7 deletions public/models/LegendModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,33 @@ const LEGEND_COLORS = [
'#b15928',
'#ffff99',
];
const LegendModel = Backbone.Model.extend({
class ArtistColor {
}
class LegendModel extends Backbone.Model {
initialize() {
this.set({ artistColors: {} });
},
}
get_artist_color(artist) {
return this.get('artistColors').get(artist.toLowerCase());
}
compute_artist_colors(scrobbles) {
let a = _.chain(scrobbles.models)
.groupBy(s => s.artist())
.groupBy(s => s.artist().toLowerCase())
.toArray()
.sortBy('length')
.reverse()
.value();
let artistColors = {};
let artistColors = new Map();
const otherColor = LEGEND_COLORS[0];
for (let i = 0; i < a.length; i++) {
let x = a[i];
artistColors[x[0].artist()] = {
artistColors.set(x[0].artist().toLowerCase(), {
artist: x[0].artist(),
color: LEGEND_COLORS[i + 1] || otherColor,
count: x.length,
showInLegend: !!LEGEND_COLORS[i + 1],
};
});
}
this.set({ artistColors, otherColor });
}
});
}
4 changes: 2 additions & 2 deletions public/models/Request.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const LastFMRequest = Backbone.Model.extend({
class LastFMRequest extends Backbone.Model {
run() {
return $.ajax({
url: "https://ws.audioscrobbler.com/2.0/",
Expand Down Expand Up @@ -30,4 +30,4 @@ const LastFMRequest = Backbone.Model.extend({
dataType: "jsonp" //, timeout: 20000. Timeout error handling is flawed.
});
}
});
}
15 changes: 8 additions & 7 deletions public/models/RequestQueue.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,18 @@
// rate limited, but not as often, and the rate limiting goes away after a few
// seconds.
const rate_limit_ms = 500;
const RequestQueue = Backbone.Model.extend({
initialize() {
class RequestQueue extends Backbone.Model {
constructor() {
super(...arguments);
this.queue = [];
this.currentlyEmptyingQueue = false;
},
}
add(req) {
this.queue.push(req);
if (!this.currentlyEmptyingQueue) {
this.doAnotherRequest();
}
},
}
doAnotherRequest() {
if (this.queue.length === 0) {
this.currentlyEmptyingQueue = false;
Expand All @@ -28,8 +29,8 @@ const RequestQueue = Backbone.Model.extend({
this.doAnotherRequest();
}, rate_limit_ms);
}
},
}
numReqsPending() {
return this.queue.size();
return this.queue.length;
}
});
}
21 changes: 12 additions & 9 deletions public/models/ScrobbleCollection.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
const Scrobble = Backbone.Model.extend({
artist() { return this.get("artist"); },
album() { return this.get("album"); },
track() { return this.get("track"); },
date() { return this.get("date"); },
class Scrobble extends Backbone.Model {
artist() { return this.get("artist"); }
album() { return this.get("album"); }
track() { return this.get("track"); }
date() { return this.get("date"); }
image() { return this.get("image"); }
});
const ScrobbleCollection = Backbone.Collection.extend({
model: Scrobble,
}
class ScrobbleCollection extends Backbone.Collection {
constructor() {
super(...arguments);
this.model = Scrobble;
}
add_from_lastfm_json(json) {
for (let scrobble of json.recenttracks.track) {
// Pull out just the information we need, because memory has been known
Expand Down Expand Up @@ -35,4 +38,4 @@ const ScrobbleCollection = Backbone.Collection.extend({
this.add(my_scrobble, { silent: true });
}
}
});
}
7 changes: 4 additions & 3 deletions public/views/DrawingThrobberView.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const DrawingThrobberView = Backbone.View.extend({
class DrawingThrobberView extends Backbone.View {
render() {
if (graphViewModel.get("isDrawing")) {
$("#drawingThrobber").show();
Expand All @@ -7,7 +7,8 @@ const DrawingThrobberView = Backbone.View.extend({
else {
$("#drawingThrobber").hide();
}
return this;
}
});
const drawingThrobberView = new DrawingThrobberView;
}
const drawingThrobberView = new DrawingThrobberView();
graphViewModel.on("change:isDrawing", (model, isDrawing) => drawingThrobberView.render());
8 changes: 5 additions & 3 deletions public/views/FetchThrobberView.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
const FetchThrobberView = Backbone.View.extend({
el: "#fetchThrobber",
class FetchThrobberView extends Backbone.View {
render() {
if (fetchModel.get("isFetching")) {
let n = fetchModel.numPagesFetched();
Expand All @@ -11,9 +10,12 @@ const FetchThrobberView = Backbone.View.extend({
else {
this.$el.hide();
}
return this;
}
}
const fetchThrobberView = new FetchThrobberView({
el: "#fetchThrobber",
});
const fetchThrobberView = new FetchThrobberView;
fetchModel.on("newPageFetched", () => fetchThrobberView.render());
fetchModel.on("change:isFetching", function (model) {
if (model.get("isFetching")) {
Expand Down
23 changes: 16 additions & 7 deletions public/views/FilterBoxView.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
const FilterBoxView = Backbone.View.extend({
el: "#searchForm",
render(isDrawn) {
if (isDrawn) {
class FilterBoxView extends Backbone.View {
constructor() {
super(...arguments);
this.isDrawn = false;
}
render() {
if (this.isDrawn) {
this.$el.fadeIn(1000);
}
else {
this.$el.hide();
}
},
return this;
}
val() { return $("#search").val(); }
}
const filterBoxView = new FilterBoxView({
el: "#searchForm",
});
graphViewModel.on("change:isDrawn", (model, isDrawn) => {
filterBoxView.isDrawn = isDrawn;
filterBoxView.render();
});
const filterBoxView = new FilterBoxView;
graphViewModel.on("change:isDrawn", (model, isDrawn) => filterBoxView.render(isDrawn));
14 changes: 9 additions & 5 deletions public/views/FlashingScrobbleView.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
const FlashingScrobbleView = Backbone.View.extend({
initialize() { this.flashingTimer = null; },
class FlashingScrobbleView extends Backbone.View {
initialize() {
this.flashingTimer = null;
}
render(scrobble) {
if (this.flashingTimer != null) {
clearInterval(this.flashingTimer);
Expand All @@ -15,7 +17,8 @@ const FlashingScrobbleView = Backbone.View.extend({
}
};
this.flashingTimer = setInterval(flash, 200);
},
return this;
}
remove() {
if (this.flashingTimer != null) {
clearInterval(this.flashingTimer);
Expand All @@ -24,9 +27,10 @@ const FlashingScrobbleView = Backbone.View.extend({
if (window.plot != null) {
window.plot.unhighlight();
}
return this;
}
});
const flashingScrobbleView = new FlashingScrobbleView;
}
const flashingScrobbleView = new FlashingScrobbleView();
$("#flot_container").on("plothover plotclick", function (event, pos, item) {
if (item) { // we're hovering over an data point
flashingScrobbleView.render(item.series.scrobble);
Expand Down
19 changes: 12 additions & 7 deletions public/views/FlotScrobbleGraphView.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const FlotScrobbleGraphView = Backbone.View.extend({
class FlotScrobbleGraphView extends Backbone.View {
render() {
if (scrobbleCollection.size() === 0) {
return;
Expand All @@ -9,17 +9,20 @@ const FlotScrobbleGraphView = Backbone.View.extend({
setTimeout(function () {
legendModel.compute_artist_colors(scrobbleCollection);
let re = appModel.filterRegex();
let filtered_scrobbles = scrobbleCollection.filter(s => re.exec(s.track()) || re.exec(s.artist()) || re.exec(s.album()));
let filtered_scrobbles = scrobbleCollection.filter(s => re.exec(s.track()) != null ||
re.exec(s.artist()) != null ||
re.exec(s.album()) != null);
let flot_series = construct_flot_series(filtered_scrobbles);
let minTime = scrobbleCollection.min(scrobble => scrobble.date()).date();
let maxTime = scrobbleCollection.max(scrobble => scrobble.date()).date();
plot_flot_series(flot_series, minTime, maxTime);
graphViewModel.set({ isDrawn: true, isDrawing: false });
}, 0);
return this;
}
});
}
var construct_flot_series = function (scrobbles) {
window.track_indices = {
const track_indices = window['track_indices'] = {
// Here's an example:
//"snow patrol#eyes open": {
//series_index: 1
Expand All @@ -31,7 +34,7 @@ var construct_flot_series = function (scrobbles) {
let date = scrobble.date().getTime();
let time = scrobble.date().getHours() + (scrobble.date().getMinutes() / 60);
series.push({
color: legendModel.get("artistColors")[scrobble.artist()].color,
color: legendModel.get_artist_color(scrobble.artist()).color,
data: [[date, time]],
scrobble
});
Expand All @@ -47,7 +50,9 @@ var construct_flot_series = function (scrobbles) {
};
var plot_flot_series = function (flot_series, minTime, maxTime) {
let ONE_DAY_IN_MS = 1000 * 60 * 60 * 24;
plot = $.plot($("#flot_container"), flot_series, {
// Don't have types for this old version of flot.
// @ts-ignore
window['plot'] = $.plot($("#flot_container"), flot_series, {
xaxis: {
min: minTime,
max: maxTime,
Expand Down Expand Up @@ -93,7 +98,7 @@ var plot_flot_series = function (flot_series, minTime, maxTime) {
}
});
};
let flotScrobbleGraphView = new FlotScrobbleGraphView;
let flotScrobbleGraphView = new FlotScrobbleGraphView();
let redraw_on_response_number = 1;
appModel.on("change:user", () => redraw_on_response_number = 1);
fetchModel.on("newPageFetched", function () {
Expand Down
16 changes: 9 additions & 7 deletions public/views/LegendView.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
const LegendView = Backbone.View.extend({
el: "#legend_wrap",
class LegendView extends Backbone.View {
render() {
this.$("li").remove();
let artistColors = legendModel.get("artistColors");
for (let artist in artistColors) {
let color = artistColors[artist];
for (const color of artistColors.values()) {
if (color.showInLegend) {
$("<li>")
.text(`${artist} (${color.count})`)
.text(`${color.artist} (${color.count})`)
.css("color", color.color)
.appendTo("#legend");
}
Expand All @@ -17,10 +15,14 @@ const LegendView = Backbone.View.extend({
.css("color", legendModel.get("otherColor"))
.appendTo("#legend");
this.$el.show();
},
return this;
}
remove() {
this.$el.hide();
return this;
}
}
const legendView = new LegendView({
el: "#legend_wrap",
});
const legendView = new LegendView;
legendModel.on("change:artistColors", (model, artistColors) => legendView.render());
Loading

0 comments on commit 69e2b8e

Please sign in to comment.