Merge branch 'master' into feature/cache_tracks

This commit is contained in:
Peter Deltchev 2015-11-05 17:15:28 -08:00
commit 5583c59ec3
17 changed files with 357 additions and 12 deletions

View file

@ -9,11 +9,14 @@ end_of_line = lf
insert_final_newline = true insert_final_newline = true
# 4 space indentation and default charset # 4 space indentation and default charset
[*.{php,coffee,js,less,css,html}] [*.{php,coffee,js,html}]
charset = utf-8 charset = utf-8
indent_style = space indent_style = space
indent_size = 4 indent_size = 4
[*.{less,css}]
indent_size = 2
# One-offs # One-offs
[{package.json}] [{package.json}]

View file

@ -23,6 +23,7 @@ namespace Poniverse\Ponyfm\Commands;
use Poniverse\Ponyfm\Album; use Poniverse\Ponyfm\Album;
use Poniverse\Ponyfm\Image; use Poniverse\Ponyfm\Image;
use Poniverse\Ponyfm\Track; use Poniverse\Ponyfm\Track;
use Poniverse\Ponyfm\TrackType;
use Poniverse\Ponyfm\User; use Poniverse\Ponyfm\User;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
@ -65,7 +66,7 @@ class EditTrackCommand extends CommandBase
'license_id' => 'required|exists:licenses,id', 'license_id' => 'required|exists:licenses,id',
'genre_id' => 'required|exists:genres,id', 'genre_id' => 'required|exists:genres,id',
'cover' => 'image|mimes:png|min_width:350|min_height:350', 'cover' => 'image|mimes:png|min_width:350|min_height:350',
'track_type_id' => 'required|exists:track_types,id', 'track_type_id' => 'required|exists:track_types,id|not_in:'.TrackType::UNCLASSIFIED_TRACK,
'songs' => 'required_when:track_type,2|exists:songs,id', 'songs' => 'required_when:track_type,2|exists:songs,id',
'cover_id' => 'exists:images,id', 'cover_id' => 'exists:images,id',
'album_id' => 'exists:albums,id' 'album_id' => 'exists:albums,id'
@ -121,7 +122,7 @@ class EditTrackCommand extends CommandBase
$track->album_id = null; $track->album_id = null;
} }
if ($track->track_type_id == 2) { if ($track->track_type_id == TrackType::OFFICIAL_TRACK_REMIX) {
$track->showSongs()->sync(explode(',', $this->_input['show_song_ids'])); $track->showSongs()->sync(explode(',', $this->_input['show_song_ids']));
} else { } else {
$track->showSongs()->sync([]); $track->showSongs()->sync([]);

View file

@ -0,0 +1,72 @@
<?php
/**
* Pony.fm - A community for pony fan music.
* Copyright (C) 2015 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/>.
*/
namespace Poniverse\Ponyfm\Console\Commands;
use Carbon\Carbon;
use DB;
use Illuminate\Console\Command;
use Poniverse\Ponyfm\Track;
use Poniverse\Ponyfm\TrackType;
class PublishUnclassifiedMlpmaTracks extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'mlpma:declassify';
/**
* The console command description.
*
* @var string
*/
protected $description = 'This publishes all unpublished MLPMA tracks as the "unclassified" track type.';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$affectedTracks = Track::mlpma()->
whereNull('published_at')
->update([
'track_type_id' => TrackType::UNCLASSIFIED_TRACK,
'published_at' => DB::raw('released_at'),
'updated_at' => Carbon::now(),
]);
$this->info("Updated ${affectedTracks} tracks.");
}
}

View file

@ -35,6 +35,7 @@ class Kernel extends ConsoleKernel
\Poniverse\Ponyfm\Console\Commands\RefreshCache::class, \Poniverse\Ponyfm\Console\Commands\RefreshCache::class,
\Poniverse\Ponyfm\Console\Commands\ImportMLPMA::class, \Poniverse\Ponyfm\Console\Commands\ImportMLPMA::class,
\Poniverse\Ponyfm\Console\Commands\ClassifyMLPMA::class, \Poniverse\Ponyfm\Console\Commands\ClassifyMLPMA::class,
\Poniverse\Ponyfm\Console\Commands\PublishUnclassifiedMlpmaTracks::class,
\Poniverse\Ponyfm\Console\Commands\RebuildTags::class, \Poniverse\Ponyfm\Console\Commands\RebuildTags::class,
\Poniverse\Ponyfm\Console\Commands\FixYearZeroLogs::class, \Poniverse\Ponyfm\Console\Commands\FixYearZeroLogs::class,
\Poniverse\Ponyfm\Console\Commands\BootstrapLocalEnvironment::class, \Poniverse\Ponyfm\Console\Commands\BootstrapLocalEnvironment::class,

View file

@ -100,7 +100,11 @@ class TracksController extends \ApiControllerBase
'small' => $track->getCoverUrl(Image::SMALL), 'small' => $track->getCoverUrl(Image::SMALL),
'normal' => $track->getCoverUrl(Image::NORMAL) 'normal' => $track->getCoverUrl(Image::NORMAL)
], ],
'comments' => $comments 'comments' => $comments,
// As of 2015-10-28, this should be expected to produce either
// "direct_upload" or "mlpma" for all tracks.
'source' => $track->source
], 200); ], 200);
} }
} }

View file

@ -36,7 +36,9 @@ class TaxonomiesController extends ApiControllerBase
'genres' => Genre::select('genres.*', 'genres' => Genre::select('genres.*',
DB::raw('(SELECT COUNT(id) FROM tracks WHERE tracks.genre_id = genres.id AND tracks.published_at IS NOT NULL) AS track_count'))->orderBy('name')->get()->toArray(), DB::raw('(SELECT COUNT(id) FROM tracks WHERE tracks.genre_id = genres.id AND tracks.published_at IS NOT NULL) AS track_count'))->orderBy('name')->get()->toArray(),
'track_types' => TrackType::select('track_types.*', 'track_types' => TrackType::select('track_types.*',
DB::raw('(SELECT COUNT(id) FROM tracks WHERE tracks.track_type_id = track_types.id AND tracks.published_at IS NOT NULL) AS track_count'))->get()->toArray(), DB::raw('(SELECT COUNT(id) FROM tracks WHERE tracks.track_type_id = track_types.id AND tracks.published_at IS NOT NULL) AS track_count'))
->where('id', '!=', TrackType::UNCLASSIFIED_TRACK)
->get()->toArray(),
'show_songs' => ShowSong::select('title', 'id', 'slug', 'show_songs' => ShowSong::select('title', 'id', 'slug',
DB::raw('(SELECT COUNT(tracks.id) FROM show_song_track INNER JOIN tracks ON tracks.id = show_song_track.track_id WHERE show_song_track.show_song_id = show_songs.id AND tracks.published_at IS NOT NULL) AS track_count'))->get()->toArray() DB::raw('(SELECT COUNT(tracks.id) FROM show_song_track INNER JOIN tracks ON tracks.id = show_song_track.track_id WHERE show_song_track.show_song_id = show_songs.id AND tracks.published_at IS NOT NULL) AS track_count'))->get()->toArray()
], 200); ], 200);

View file

@ -24,6 +24,7 @@ use Auth;
use Cache; use Cache;
use Config; use Config;
use DB; use DB;
use Poniverse\Ponyfm\Traits\SlugTrait;
use Exception; use Exception;
use External; use External;
use getid3_writetags; use getid3_writetags;
@ -32,7 +33,6 @@ use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Log; use Log;
use Poniverse\Ponyfm\Traits\SlugTrait;
use URL; use URL;
class Track extends Model class Track extends Model
@ -155,6 +155,16 @@ class Track extends Model
]); ]);
} }
/**
* Limits results to MLP Music Archive tracks.
*
* @param $query
*/
public function scopeMlpma($query)
{
$query->join('mlpma_tracks', 'tracks.id', '=', 'mlpma_tracks.track_id');
}
public static function popular($count, $allowExplicit = false) public static function popular($count, $allowExplicit = false)
{ {
$trackIds = Cache::remember('popular_tracks' . $count . '-' . ($allowExplicit ? 'explicit' : 'safe'), 5, $trackIds = Cache::remember('popular_tracks' . $count . '-' . ($allowExplicit ? 'explicit' : 'safe'), 5,

View file

@ -31,4 +31,5 @@ class TrackType extends Model
const FAN_TRACK_REMIX = 3; const FAN_TRACK_REMIX = 3;
const PONIFIED_TRACK = 4; const PONIFIED_TRACK = 4;
const OFFICIAL_AUDIO_REMIX = 5; const OFFICIAL_AUDIO_REMIX = 5;
const UNCLASSIFIED_TRACK = 6;
} }

View file

@ -0,0 +1,57 @@
<?php
/**
* Pony.fm - A community for pony fan music.
* Copyright (C) 2015 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;
class AddTrackSourceColumn extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('tracks', function(Blueprint $table){
$table->string('source', 40)->default('direct_upload');
});
// Mark MLPMA tracks retroactively
// --> The default value in the database, set above, will
// be used automatically for all non-MLPMA tracks.
$tracks = DB::table('tracks')
->join('mlpma_tracks', 'mlpma_tracks.track_id', '=', 'tracks.id');
$tracks->whereNotNull('mlpma_tracks.id')->update(['source' => 'mlpma']);
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('tracks', function(Blueprint $table){
$table->dropColumn('source');
});
}
}

View file

@ -0,0 +1,68 @@
<?php
/**
* Pony.fm - A community for pony fan music.
* Copyright (C) 2015 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\Track;
class AddTrackFilesForDeletedTracks extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
// 2015_05_25_011121_create_track_files_table.php only created
// track_files records for non-deleted tracks. This migration
// adds them for deleted tracks, too.
$tracks = Track::with('trackFiles')
->onlyTrashed()
->get();
foreach ($tracks as $track) {
if ($track->trackFiles->count() === 0 && $track->source !== 'mlpma') {
foreach (Track::$Formats as $name => $item) {
DB::table('track_files')->insert(
[
'track_id' => $track->id,
'is_master' => $name === 'FLAC' ? true : false,
'format' => $name,
'created_at' => $track->created_at,
'updated_at' => Carbon\Carbon::now()
]
);
}
}
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
// There's no need to undo this one!
}
}

View file

@ -0,0 +1,49 @@
<?php
/**
* Pony.fm - A community for pony fan music.
* Copyright (C) 2015 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;
class AddUnclassifiedTrackType extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
DB::table('track_types')->insert([
'id' => 6,
'title' => 'Unclassified',
'editor_title' => 'an unclassified track'
]);
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
DB::table('track_types')->where('id', 6)->delete();
}
}

View file

@ -66,6 +66,12 @@
<a href="#" ng-click="gotoPage(page);" pfm-eat-click>{{page}}</a> <a href="#" ng-click="gotoPage(page);" pfm-eat-click>{{page}}</a>
</li> </li>
<li ng-class="{disabled: !nextPage}"><a href="#" ng-click="gotoPage(nextPage);" pfm-eat-click>Next</a></li> <li ng-class="{disabled: !nextPage}"><a href="#" ng-click="gotoPage(nextPage);" pfm-eat-click>Next</a></li>
<li class="pagination-jump">
<a href="#" ng-click="showPageSelector();" ng-hide="pageSelectorShown" pfm-eat-click>Jump&hellip;</a>
<form ng-submit="jumpToPage()" ng-show="pageSelectorShown">
<input type="number" id="pagination-jump-destination" ng-model="inputPageNumber" ng-blur="hidePageSelector()">
</form>
</li>
</ul> </ul>
</div> </div>

View file

@ -21,8 +21,8 @@ window.pfm.preloaders['tracks'] = [
] ]
angular.module('ponyfm').controller "tracks", [ angular.module('ponyfm').controller "tracks", [
'$scope', 'tracks', '$state' '$scope', 'tracks', '$state', 'focus'
($scope, tracks, $state) -> ($scope, tracks, $state, focus) ->
$scope.recentTracks = null $scope.recentTracks = null
$scope.query = tracks.mainQuery $scope.query = tracks.mainQuery
$scope.filters = tracks.filters $scope.filters = tracks.filters
@ -52,10 +52,40 @@ angular.module('ponyfm').controller "tracks", [
$scope.nextPage = $scope.currentPage + 1 if $scope.currentPage < $scope.totalPages $scope.nextPage = $scope.currentPage + 1 if $scope.currentPage < $scope.totalPages
$scope.prevPage = $scope.currentPage - 1 if $scope.currentPage > 1 $scope.prevPage = $scope.currentPage - 1 if $scope.currentPage > 1
$scope.pages = [1..$scope.totalPages] $scope.allPages = [1..$scope.totalPages]
# TODO: turn this into a directive
# The actual first page will always be in the paginator.
$scope.pages = [1]
# This logic determines how many pages to add prior to the current page, if any.
firstPage = Math.max(2, $scope.currentPage-3)
$scope.pages = $scope.pages.concat [firstPage..$scope.currentPage] unless $scope.currentPage == 1
pagesLeftToAdd = 8-$scope.pages.length
lastPage = Math.min($scope.totalPages - 1, $scope.currentPage+1+pagesLeftToAdd)
$scope.pages = $scope.pages.concat([$scope.currentPage+1..lastPage]) unless $scope.currentPage >= lastPage
# The actual last page will always be in the paginator.
$scope.pages.push($scope.totalPages) unless $scope.totalPages in $scope.pages
$scope.pageSelectorShown = false
$scope.inputPageNumber = $scope.currentPage
$scope.gotoPage = (page) -> $scope.gotoPage = (page) ->
$state.transitionTo 'content.tracks.list', {filter: $state.params.filter, page: page} $state.transitionTo 'content.tracks.list', {filter: $state.params.filter, page: page}
$scope.showPageSelector = () ->
$scope.pageSelectorShown = true
focus('#pagination-jump-destination')
$scope.hidePageSelector = () ->
$scope.pageSelectorShown = false
$scope.jumpToPage = () ->
$scope.gotoPage($scope.inputPageNumber)
$scope.$on '$destroy', -> tracks.mainQuery = tracks.createQuery() $scope.$on '$destroy', -> tracks.mainQuery = tracks.createQuery()
] ]

View file

@ -0,0 +1,27 @@
# Pony.fm - A community for pony fan music.
# Copyright (C) 2015 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/>.
# This service provides a way to set the browser's focus to a particular element
# using a jQuery selector.
#
# Based on: https://stackoverflow.com/a/25597540/3225811
angular.module('ponyfm').factory('focus', ['$timeout', '$window', ($timeout, $window) ->
(selector) ->
$timeout () ->
element = $window.jQuery("#{selector}")
element.focus() # will do nothing if the selector doesn't select anything
])

View file

@ -408,4 +408,18 @@ html {
float: right; float: right;
} }
} }
.pagination-jump {
form {
margin: 0;
}
input[type="number"] {
margin: 0;
height: 22px;
width: 60px;
padding: 0 5px;
text-align: center;
}
}
} }

View file

@ -51,13 +51,13 @@ label.strong {
font-weight: bold; font-weight: bold;
} }
input[type="text"], input[type="password"], input[type="date"], textarea { input[type="text"], input[type="password"], input[type="date"], input[type="number"], textarea {
padding: 3px; padding: 3px;
border: 1px solid; border: 1px solid;
border-color: #9c9c9c #9c9c9c #ccc #ccc; border-color: #9c9c9c #9c9c9c #ccc #ccc;
} }
input[type="text"], input[type="password"], input[type="date"], textarea, select { input[type="text"], input[type="password"], input[type="date"], input[type="number"], textarea, select {
.border-radius(0px); .border-radius(0px);
.box-sizing(border-box); .box-sizing(border-box);

View file

@ -99,7 +99,7 @@
<li><a href="/register" target="_self">Register</a></li> <li><a href="/register" target="_self">Register</a></li>
@endif @endif
<li class="x-attribution"> <li class="x-attribution">
<a ng-click="showCredits()" href="#" title="Pony.fm project credits"> <a ng-click="showCredits()" title="Pony.fm project credits">
@if(config('ponyfm.use_powered_by_footer')) @if(config('ponyfm.use_powered_by_footer'))
<span>Powered by</span> <span>Powered by</span>
<img src="/images/ponyfm-logo-white.svg" alt="Pony.fm logo" title="Pony.fm"/> <img src="/images/ponyfm-logo-white.svg" alt="Pony.fm logo" title="Pony.fm"/>