mirror of
https://github.com/Poniverse/Pony.fm.git
synced 2024-11-25 14:37:59 +01:00
#56: Fixed duplicate tracks in playlists.
This commit is contained in:
parent
d73a0d006d
commit
a2b35ba8a3
5 changed files with 136 additions and 10 deletions
|
@ -22,12 +22,16 @@ namespace Poniverse\Ponyfm\Commands;
|
||||||
|
|
||||||
use Poniverse\Ponyfm\Models\Playlist;
|
use Poniverse\Ponyfm\Models\Playlist;
|
||||||
use Poniverse\Ponyfm\Models\Track;
|
use Poniverse\Ponyfm\Models\Track;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Auth;
|
||||||
use Illuminate\Support\Facades\DB;
|
use DB;
|
||||||
|
use Validator;
|
||||||
|
|
||||||
class AddTrackToPlaylistCommand extends CommandBase
|
class AddTrackToPlaylistCommand extends CommandBase
|
||||||
{
|
{
|
||||||
|
/** @var Track */
|
||||||
private $_track;
|
private $_track;
|
||||||
|
|
||||||
|
/** @var Playlist */
|
||||||
private $_playlist;
|
private $_playlist;
|
||||||
|
|
||||||
function __construct($playlistId, $trackId)
|
function __construct($playlistId, $trackId)
|
||||||
|
@ -52,11 +56,22 @@ class AddTrackToPlaylistCommand extends CommandBase
|
||||||
*/
|
*/
|
||||||
public function execute()
|
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;
|
$songIndex = $this->_playlist->tracks()->count() + 1;
|
||||||
$this->_playlist->tracks()->attach($this->_track, ['position' => $songIndex]);
|
$this->_playlist->tracks()->attach($this->_track, ['position' => $songIndex]);
|
||||||
$this->_playlist->touch();
|
$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 . ')')
|
'track_count' => DB::raw('(SELECT COUNT(id) FROM playlist_track WHERE playlist_id = ' . $this->_playlist->id . ')')
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
|
@ -169,8 +169,12 @@ class PlaylistsController extends ApiControllerBase
|
||||||
|
|
||||||
public function getOwned()
|
public function getOwned()
|
||||||
{
|
{
|
||||||
$query = Playlist::summary()->with('pins', 'tracks', 'tracks.cover')->where('user_id',
|
$query = Playlist::summary()
|
||||||
\Auth::user()->id)->orderBy('title', 'asc')->get();
|
->with('pins', 'tracks', 'tracks.cover')
|
||||||
|
->where('user_id', Auth::user()->id)
|
||||||
|
->orderBy('title', 'asc')
|
||||||
|
->get();
|
||||||
|
|
||||||
$playlists = [];
|
$playlists = [];
|
||||||
foreach ($query as $playlist) {
|
foreach ($query as $playlist) {
|
||||||
$playlists[] = [
|
$playlists[] = [
|
||||||
|
@ -185,7 +189,8 @@ class PlaylistsController extends ApiControllerBase
|
||||||
'normal' => $playlist->getCoverUrl(Image::NORMAL)
|
'normal' => $playlist->getCoverUrl(Image::NORMAL)
|
||||||
],
|
],
|
||||||
'is_pinned' => $playlist->hasPinFor(Auth::user()->id),
|
'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')
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,7 +25,11 @@
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li bindonce ng-repeat="playlist in playlists">
|
<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-hide="playlist.message" bo-text="playlist.title"></span>
|
||||||
<span ng-show="playlist.message">{{playlist.message}}</span>
|
<span ng-show="playlist.message">{{playlist.message}}</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -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', 'download-cached', '$window', '$timeout'
|
||||||
($scope, $rootScope, tracks, $state, playlists, auth, favourites, $dialog, cachedTrack, $window, $timeout) ->
|
($scope, $rootScope, tracks, $state, playlists, auth, favourites, $dialog, cachedTrack, $window, $timeout) ->
|
||||||
track = null
|
track = null
|
||||||
|
trackId = parseInt($state.params.id)
|
||||||
|
|
||||||
tracks.fetch($state.params.id).done (trackResponse) ->
|
tracks.fetch(trackId).done (trackResponse) ->
|
||||||
$scope.track = trackResponse.track
|
$scope.track = trackResponse.track
|
||||||
track = trackResponse.track
|
track = trackResponse.track
|
||||||
$rootScope.description = "Listen to #{track.title} by #{track.user.name} on the largest pony music site"
|
$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 = []
|
$scope.playlists = []
|
||||||
|
|
||||||
if auth.data.isLogged
|
if auth.data.isLogged
|
||||||
playlists.refreshOwned().done (lists) ->
|
playlists.refreshOwned().done (playlists) ->
|
||||||
$scope.playlists.push list for list in lists
|
for playlist in playlists
|
||||||
|
if trackId not in playlist.track_ids
|
||||||
|
$scope.playlists.push playlist
|
||||||
|
|
||||||
$scope.favouriteWorking = false
|
$scope.favouriteWorking = false
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue