#56: Fixed duplicate tracks in playlists.

This commit is contained in:
Peter Deltchev 2016-01-23 04:20:18 -08:00
parent d73a0d006d
commit a2b35ba8a3
5 changed files with 136 additions and 10 deletions

View file

@ -22,12 +22,16 @@ namespace Poniverse\Ponyfm\Commands;
use Poniverse\Ponyfm\Models\Playlist;
use Poniverse\Ponyfm\Models\Track;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Auth;
use DB;
use Validator;
class AddTrackToPlaylistCommand extends CommandBase
{
/** @var Track */
private $_track;
/** @var Playlist */
private $_playlist;
function __construct($playlistId, $trackId)
@ -52,11 +56,22 @@ class AddTrackToPlaylistCommand extends CommandBase
*/
public function execute()
{
// check if this track is already in the playlist
$validator = Validator::make(
['track_id' => $this->_track->id],
['track_id' => "unique:playlist_track,track_id,null,id,playlist_id,{$this->_playlist->id}",]
);
if ($validator->fails()) {
return CommandResponse::fail($validator);
}
$songIndex = $this->_playlist->tracks()->count() + 1;
$this->_playlist->tracks()->attach($this->_track, ['position' => $songIndex]);
$this->_playlist->touch();
Playlist::whereId($this->_playlist->id)->update([
Playlist::where('id', $this->_playlist->id)->update([
'track_count' => DB::raw('(SELECT COUNT(id) FROM playlist_track WHERE playlist_id = ' . $this->_playlist->id . ')')
]);

View file

@ -169,8 +169,12 @@ class PlaylistsController extends ApiControllerBase
public function getOwned()
{
$query = Playlist::summary()->with('pins', 'tracks', 'tracks.cover')->where('user_id',
\Auth::user()->id)->orderBy('title', 'asc')->get();
$query = Playlist::summary()
->with('pins', 'tracks', 'tracks.cover')
->where('user_id', Auth::user()->id)
->orderBy('title', 'asc')
->get();
$playlists = [];
foreach ($query as $playlist) {
$playlists[] = [
@ -185,7 +189,8 @@ class PlaylistsController extends ApiControllerBase
'normal' => $playlist->getCoverUrl(Image::NORMAL)
],
'is_pinned' => $playlist->hasPinFor(Auth::user()->id),
'is_public' => $playlist->is_public == 1
'is_public' => $playlist->is_public == 1,
'track_ids' => $playlist->tracks->pluck('id')
];
}

View file

@ -0,0 +1,99 @@
<?php
/**
* Pony.fm - A community for pony fan music.
* Copyright (C) 2016 Peter Deltchev
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use Poniverse\Ponyfm\Models\Playlist;
class EnforceUniqueTracksInPlaylists extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
DB::transaction(function(){
$playlistIds = DB::table('playlists')->lists('id');
foreach ($playlistIds as $playlistId) {
/** @var Playlist $playlist */
// Deletes all of a playlist's entries of a
// duplicate track except for the first one.
$ids = DB::select(
DB::raw(
<<<EOF
SELECT id,position FROM playlist_track
WHERE playlist_id = ?
AND track_id IN
(
SELECT track_id FROM
(
SELECT track_id,COUNT(*) as count FROM playlist_track
WHERE playlist_id = ?
GROUP BY track_id
) as duplicateTracks
WHERE count > 1
)
ORDER BY position ASC
LIMIT 1,18446744073709551615
EOF
)
, [$playlistId, $playlistId]);
$ids = collect($ids)->pluck('id');
DB::table('playlist_track')
->whereIn('id', $ids)
->delete();
// Using this instead of $model->fresh(); because that
// doesn't deal with soft-deleted models.
$playlist = Playlist::with('tracks')->withTrashed()->find($playlistId);
$position = 1;
foreach($playlist->tracks as $track) {
$track->pivot->position = $position;
$track->pivot->save();
$position++;
}
}
});
Schema::table('playlist_track', function(Blueprint $table) {
$table->unique(['playlist_id', 'track_id']);
});
Artisan::call('refresh-cache');
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('playlist_track', function (Blueprint $table) {
$table->dropUnique('playlist_track_playlist_id_track_id_unique');
});
}
}

View file

@ -25,7 +25,11 @@
</a>
<ul class="dropdown-menu">
<li bindonce ng-repeat="playlist in playlists">
<a ng-class="{disabled: playlist.message, 'btn-success': playlist.message}" bo-href="playlist.url" pfm-eat-click ng-click="addToPlaylist(playlist); $event.stopPropagation()">
<a ng-class="{disabled: playlist.message, 'btn-success': playlist.message}"
bo-href="playlist.url"
pfm-eat-click
ng-click="addToPlaylist(playlist); $event.stopPropagation()"
>
<span ng-hide="playlist.message" bo-text="playlist.title"></span>
<span ng-show="playlist.message">{{playlist.message}}</span>
</a>

View file

@ -24,8 +24,9 @@ angular.module('ponyfm').controller "track", [
'$scope', '$rootScope', 'tracks', '$state', 'playlists', 'auth', 'favourites', '$dialog', 'download-cached', '$window', '$timeout'
($scope, $rootScope, tracks, $state, playlists, auth, favourites, $dialog, cachedTrack, $window, $timeout) ->
track = null
trackId = parseInt($state.params.id)
tracks.fetch($state.params.id).done (trackResponse) ->
tracks.fetch(trackId).done (trackResponse) ->
$scope.track = trackResponse.track
track = trackResponse.track
$rootScope.description = "Listen to #{track.title} by #{track.user.name} on the largest pony music site"
@ -33,8 +34,10 @@ angular.module('ponyfm').controller "track", [
$scope.playlists = []
if auth.data.isLogged
playlists.refreshOwned().done (lists) ->
$scope.playlists.push list for list in lists
playlists.refreshOwned().done (playlists) ->
for playlist in playlists
if trackId not in playlist.track_ids
$scope.playlists.push playlist
$scope.favouriteWorking = false