added support for song track numbers as well as subsorting song lists

with a second sort key. track numbers are also editable via the song
edit modal interface.
This commit is contained in:
alex-phillips 2016-03-20 08:58:14 -04:00
parent 8c7dae6a32
commit 940cd1a914
7 changed files with 57 additions and 7 deletions

View file

@ -133,10 +133,12 @@ class Song extends Model
continue;
}
// If we're updating only one song, take into account the title and lyrics.
// If we're updating only one song, take into account the title and lyrics
// and track number.
if (count($ids) === 1) {
$song->title = trim($data['title']) ?: $song->title;
$song->lyrics = trim($data['lyrics']);
$song->track = trim($data['track']);
}
// If "newArtist" is provided, we'll see if such an artist name is found in our database.

View file

@ -229,11 +229,19 @@ class Media
return;
}
$track = array_get($info, 'comments.track_number', [0])[0];
if (preg_match('#(\d+)/#', $track, $matches)) {
$track = $matches[1];
} elseif ((int) $track) {
$track = (int) $track;
}
$props = [
'artist' => '',
'album' => '',
'title' => '',
'length' => $info['playtime_seconds'],
'track' => $track,
'lyrics' => '',
'cover' => array_get($info, 'comments.picture', [null])[0],
'path' => $file->getPathname(),

View file

@ -35,6 +35,7 @@ $factory->define(App\Models\Song::class, function ($faker) {
return [
'title' => $faker->sentence,
'length' => $faker->randomFloat(2, 10, 500),
'track' => $faker->randomNumber(),
'lyrics' => $faker->paragraph(),
'path' => '/tmp/'.uniqid().'.mp3',
'mtime' => time(),

View file

@ -17,6 +17,7 @@ class CreateSongsTable extends Migration
$table->integer('album_id')->unsigned();
$table->string('title');
$table->float('length');
$table->integer('track');
$table->text('lyrics');
$table->text('path');
$table->integer('mtime');

View file

@ -280,7 +280,7 @@
*
* @source https://github.com/vuejs/vue/blob/dev/src/filters/array-filters.js
*/
Vue.filter('caseInsensitiveOrderBy', (arr, sortKey, reverse) => {
Vue.filter('caseInsensitiveOrderBy', (arr, sortKey, reverse, subSortKey) => {
if (!sortKey) {
return arr;
}
@ -289,17 +289,45 @@
// sort on a copy to avoid mutating original array
return arr.slice().sort((a, b) => {
let aSub = subSortKey ? Vue.util.isObject(a) ? Vue.parsers.path.getPath(a, subSortKey) : 0 : 0;
let bSub = subSortKey ? Vue.util.isObject(b) ? Vue.parsers.path.getPath(b, subSortKey) : 0 : 0;
a = Vue.util.isObject(a) ? Vue.parsers.path.getPath(a, sortKey) : a;
b = Vue.util.isObject(b) ? Vue.parsers.path.getPath(b, sortKey) : b;
if (_.isNumber(a) && _.isNumber(b)) {
return a === b ? 0 : a > b ? order : -order;
if (a === b) {
if (_.isNumber(aSub) && _.isNumber(bSub)) {
return aSub === bSub ? 0 : aSub > bSub ? order : -order;
} else if (aSub !== undefined && bSub !== undefined) {
aSub = aSub.toLowerCase();
bSub = bSub.toLowerCase();
return aSub === bSub ? 0 : aSub > bSub ? order : -order;
}
return 0;
}
return a > b ? order : -order;
}
a = a === undefined ? a : a.toLowerCase();
b = b === undefined ? b : b.toLowerCase();
return a === b ? 0 : a > b ? order : -order;
if (a === b) {
if (_.isNumber(aSub) && _.isNumber(bSub)) {
return aSub === bSub ? 0 : aSub > bSub ? order : -order;
} else if (aSub !== undefined && bSub !== undefined) {
aSub = aSub.toLowerCase();
bSub = bSub.toLowerCase();
return aSub === bSub ? 0 : aSub > bSub ? order : -order;
}
return 0;
}
return a > b ? order : -order;
});
});

View file

@ -44,6 +44,10 @@
:options="albumTypeaheadOptions"
:value.sync="formData.albumName"></typeahead>
</div>
<div class="form-row" v-show="editSingle">
<label>Track</label>
<input type="text" v-model="formData.track">
</div>
</div>
<div v-show="currentView === 'lyrics' && editSingle">
<div class="form-row">
@ -106,6 +110,7 @@
albumName: '',
artistName: '',
lyrics: '',
track: '',
},
};
},
@ -197,9 +202,11 @@
songStore.getInfo(this.songs[0], () => {
this.loading = false;
this.formData.lyrics = utils.br2nl(this.songs[0].lyrics);
this.formData.track = this.songs[0].track;
});
} else {
this.formData.lyrics = utils.br2nl(this.songs[0].lyrics);
this.formData.track = this.songs[0].track;
}
} else {
this.formData.albumName = this.inSameAlbum ? this.songs[0].album.name : '';

View file

@ -18,7 +18,7 @@
<i class="fa fa-angle-down" v-show="sortKey === 'album.artist.name' && order > 0"></i>
<i class="fa fa-angle-up" v-show="sortKey === 'album.artist.name' && order < 0"></i>
</th>
<th @click="sort('album.name')">Album
<th @click="sort('album.name', 'track')">Album
<i class="fa fa-angle-down" v-show="sortKey === 'album.name' && order > 0"></i>
<i class="fa fa-angle-up" v-show="sortKey === 'album.name' && order < 0"></i>
</th>
@ -33,10 +33,11 @@
<tbody>
<tr
v-for="item in items
| caseInsensitiveOrderBy sortKey order
| caseInsensitiveOrderBy sortKey order subSortKey
| filterSongBy q
| limitBy numOfItems"
is="song-item"
data-track="{{ item.track }}"
data-song-id="{{ item.id }}"
track-by="id"
:song="item"
@ -81,6 +82,7 @@
lastSelectedRow: null,
q: '', // The filter query
sortKey: this.type === 'top-songs' ? 'playCount' : '',
subSortKey: 0,
order: this.type === 'top-songs' ? -1 : 1,
componentCache: {},
};
@ -109,12 +111,13 @@
*
* @param {String} key The sort key. Can be 'title', 'album', 'artist', or 'fmtLength'
*/
sort(key) {
sort(key, subSortKey) {
if (this.sortable === false) {
return;
}
this.sortKey = key;
this.subSortKey = subSortKey ? subSortKey : 0;
this.order = 0 - this.order;
},