mirror of
https://github.com/Poniverse/Pony.fm.git
synced 2025-02-07 06:16:43 +01:00
Merge pull request #54 from Poniverse/feature/search
#1: The search feature
This commit is contained in:
commit
bfc17a2edb
40 changed files with 1773 additions and 233 deletions
|
@ -54,6 +54,7 @@ class AddTrackToPlaylistCommand extends CommandBase
|
|||
{
|
||||
$songIndex = $this->_playlist->tracks()->count() + 1;
|
||||
$this->_playlist->tracks()->attach($this->_track, ['position' => $songIndex]);
|
||||
$this->_playlist->touch();
|
||||
|
||||
Playlist::whereId($this->_playlist->id)->update([
|
||||
'track_count' => DB::raw('(SELECT COUNT(id) FROM playlist_track WHERE playlist_id = ' . $this->_playlist->id . ')')
|
||||
|
|
121
app/Console/Commands/RebuildSearchIndex.php
Normal file
121
app/Console/Commands/RebuildSearchIndex.php
Normal file
|
@ -0,0 +1,121 @@
|
|||
<?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/>.
|
||||
*/
|
||||
|
||||
namespace Poniverse\Ponyfm\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Poniverse\Ponyfm\Models\Album;
|
||||
use Poniverse\Ponyfm\Models\Playlist;
|
||||
use Poniverse\Ponyfm\Models\Track;
|
||||
use Poniverse\Ponyfm\Models\User;
|
||||
use Symfony\Component\Console\Helper\ProgressBar;
|
||||
|
||||
class RebuildSearchIndex extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'rebuild:search';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Rebuilds the Elasticsearch index.';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$totalTracks = Track::withTrashed()->count();
|
||||
$totalAlbums = Album::withTrashed()->count();
|
||||
$totalPlaylists = Playlist::withTrashed()->count();
|
||||
$totalUsers = User::count();
|
||||
|
||||
$trackProgress = $this->output->createProgressBar($totalTracks);
|
||||
$this->info("Processing tracks...");
|
||||
Track::withTrashed()->chunk(200, function(Collection $tracks) use ($trackProgress) {
|
||||
foreach($tracks as $track) {
|
||||
/** @var Track $track */
|
||||
$trackProgress->advance();
|
||||
$track->updateElasticsearchEntry();
|
||||
}
|
||||
});
|
||||
$trackProgress->finish();
|
||||
$this->line('');
|
||||
|
||||
|
||||
$albumProgress = $this->output->createProgressBar($totalAlbums);
|
||||
$this->info("Processing albums...");
|
||||
Album::withTrashed()->chunk(200, function(Collection $albums) use ($albumProgress) {
|
||||
foreach($albums as $album) {
|
||||
/** @var Album $album */
|
||||
$albumProgress->advance();
|
||||
$album->updateElasticsearchEntry();
|
||||
}
|
||||
});
|
||||
$albumProgress->finish();
|
||||
$this->line('');
|
||||
|
||||
|
||||
$playlistProgress = $this->output->createProgressBar($totalPlaylists);
|
||||
$this->info("Processing playlists...");
|
||||
Playlist::withTrashed()->chunk(200, function(Collection $playlists) use ($playlistProgress) {
|
||||
foreach($playlists as $playlist) {
|
||||
/** @var Playlist $playlist */
|
||||
$playlistProgress->advance();
|
||||
$playlist->updateElasticsearchEntry();
|
||||
}
|
||||
});
|
||||
$playlistProgress->finish();
|
||||
$this->line('');
|
||||
|
||||
|
||||
$userProgress = $this->output->createProgressBar($totalUsers);
|
||||
$this->info("Processing users...");
|
||||
User::chunk(200, function(Collection $users) use ($userProgress) {
|
||||
foreach($users as $user) {
|
||||
/** @var User $user */
|
||||
$userProgress->advance();
|
||||
$user->updateElasticsearchEntry();
|
||||
}
|
||||
});
|
||||
$userProgress->finish();
|
||||
$this->line('');
|
||||
$this->info('Everything has been queued for re-indexing!');
|
||||
}
|
||||
}
|
|
@ -42,6 +42,7 @@ class Kernel extends ConsoleKernel
|
|||
\Poniverse\Ponyfm\Console\Commands\RebuildTrackCache::class,
|
||||
\Poniverse\Ponyfm\Console\Commands\RebuildTrack::class,
|
||||
\Poniverse\Ponyfm\Console\Commands\RebuildFilesizes::class,
|
||||
\Poniverse\Ponyfm\Console\Commands\RebuildSearchIndex::class,
|
||||
\Poniverse\Ponyfm\Console\Commands\MergeDuplicateAccounts::class,
|
||||
];
|
||||
|
||||
|
|
39
app/Contracts/Searchable.php
Normal file
39
app/Contracts/Searchable.php
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?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/>.
|
||||
*/
|
||||
|
||||
namespace Poniverse\Ponyfm\Contracts;
|
||||
|
||||
interface Searchable {
|
||||
/**
|
||||
* Returns this model in Elasticsearch-friendly form. The array returned by
|
||||
* this method should match the current mapping for this model's ES type.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toElasticsearch():array;
|
||||
|
||||
/**
|
||||
* @return bool whether this particular object should be indexed or not
|
||||
*/
|
||||
public function shouldBeIndexed():bool;
|
||||
|
||||
public function updateElasticsearchEntry();
|
||||
public function updateElasticsearchEntrySynchronously();
|
||||
}
|
|
@ -195,18 +195,7 @@ class ArtistsController extends ApiControllerBase
|
|||
$users = [];
|
||||
|
||||
foreach ($query->get() as $user) {
|
||||
$users[] = [
|
||||
'id' => $user->id,
|
||||
'name' => $user->display_name,
|
||||
'slug' => $user->slug,
|
||||
'url' => $user->url,
|
||||
'is_archived' => $user->is_archived,
|
||||
'avatars' => [
|
||||
'small' => $user->getAvatarUrl(Image::SMALL),
|
||||
'normal' => $user->getAvatarUrl(Image::NORMAL)
|
||||
],
|
||||
'created_at' => $user->created_at
|
||||
];
|
||||
$users[] = User::mapPublicUserSummary($user);
|
||||
}
|
||||
|
||||
return Response::json(["artists" => $users, "current_page" => $page, "total_pages" => ceil($count / $perPage)],
|
||||
|
|
39
app/Http/Controllers/Api/Web/SearchController.php
Normal file
39
app/Http/Controllers/Api/Web/SearchController.php
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?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/>.
|
||||
*/
|
||||
|
||||
namespace Poniverse\Ponyfm\Http\Controllers\Api\Web;
|
||||
|
||||
use Elasticsearch;
|
||||
use Poniverse\Ponyfm\Http\Controllers\ApiControllerBase;
|
||||
use Input;
|
||||
use Poniverse\Ponyfm\Library\Search;
|
||||
use Response;
|
||||
|
||||
class SearchController extends ApiControllerBase
|
||||
{
|
||||
public function getSearch(Search $search)
|
||||
{
|
||||
$results = $search->searchAllContent(Input::query('query'));
|
||||
|
||||
return Response::json([
|
||||
'results' => $results,
|
||||
], 200);
|
||||
}
|
||||
}
|
|
@ -82,8 +82,7 @@ Route::group(['prefix' => 'api/v1', 'middleware' => 'json-exceptions'], function
|
|||
|
||||
Route::group(['prefix' => 'api/web'], function() {
|
||||
Route::get('/taxonomies/all', 'Api\Web\TaxonomiesController@getAll');
|
||||
|
||||
Route::get('/playlists/show/{id}', 'Api\Web\PlaylistsController@getShow');
|
||||
Route::get('/search', ['middleware' => ['auth', 'can:access-search'], 'uses' => 'Api\Web\SearchController@getSearch']);
|
||||
|
||||
Route::get('/tracks', 'Api\Web\TracksController@getIndex');
|
||||
Route::get('/tracks/{id}', 'Api\Web\TracksController@getShow')->where('id', '\d+');
|
||||
|
@ -94,6 +93,7 @@ Route::group(['prefix' => 'api/web'], function() {
|
|||
Route::get('/albums/cached/{id}/{format}', 'Api\Web\AlbumsController@getCachedAlbum')->where(['id' => '\d+', 'format' => '.+']);
|
||||
|
||||
Route::get('/playlists', 'Api\Web\PlaylistsController@getIndex');
|
||||
Route::get('/playlists/show/{id}', 'Api\Web\PlaylistsController@getShow');
|
||||
Route::get('/playlists/{id}', 'Api\Web\PlaylistsController@getShow')->where('id', '\d+');
|
||||
Route::get('/playlists/cached/{id}/{format}', 'Api\Web\PlaylistsController@getCachedPlaylist')->where(['id' => '\d+', 'format' => '.+']);
|
||||
|
||||
|
|
56
app/Jobs/UpdateSearchIndexForEntity.php
Normal file
56
app/Jobs/UpdateSearchIndexForEntity.php
Normal file
|
@ -0,0 +1,56 @@
|
|||
<?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/>.
|
||||
*/
|
||||
|
||||
namespace Poniverse\Ponyfm\Jobs;
|
||||
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Poniverse\Ponyfm\Contracts\Searchable;
|
||||
use Poniverse\Ponyfm\Jobs\Job;
|
||||
use Illuminate\Contracts\Bus\SelfHandling;
|
||||
use SerializesModels;
|
||||
|
||||
class UpdateSearchIndexForEntity extends Job implements SelfHandling, ShouldQueue
|
||||
{
|
||||
use InteractsWithQueue, SerializesModels;
|
||||
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @param Model $entity
|
||||
*/
|
||||
public function __construct(Searchable $entity)
|
||||
{
|
||||
$this->entity = $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$this->entity->updateElasticsearchEntrySynchronously();
|
||||
}
|
||||
}
|
206
app/Library/Search.php
Normal file
206
app/Library/Search.php
Normal file
|
@ -0,0 +1,206 @@
|
|||
<?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/>.
|
||||
*/
|
||||
|
||||
namespace Poniverse\Ponyfm\Library;
|
||||
|
||||
use DB;
|
||||
use Elasticsearch\Client;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Poniverse\Ponyfm\Models\Album;
|
||||
use Poniverse\Ponyfm\Models\Playlist;
|
||||
use Poniverse\Ponyfm\Models\Track;
|
||||
use Poniverse\Ponyfm\Models\User;
|
||||
|
||||
class Search {
|
||||
protected $elasticsearch;
|
||||
protected $index;
|
||||
|
||||
public function __construct(Client $connection, string $indexName) {
|
||||
$this->elasticsearch = $connection;
|
||||
$this->index = $indexName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @param int $resultsPerContentType
|
||||
* @return array
|
||||
*/
|
||||
public function searchAllContent(string $query) {
|
||||
$results = $this->elasticsearch->msearch([
|
||||
'index' => $this->index,
|
||||
'body' => [
|
||||
//===== Tracks=====//
|
||||
['type' => 'track'],
|
||||
[
|
||||
'query' => [
|
||||
'multi_match' => [
|
||||
'query' => $query,
|
||||
'fields' => [
|
||||
'title^3',
|
||||
'artist^2',
|
||||
'genre',
|
||||
'track_type',
|
||||
'show_songs^2',
|
||||
],
|
||||
'tie_breaker' => 0.3,
|
||||
],
|
||||
],
|
||||
'size' => 11
|
||||
],
|
||||
|
||||
//===== Albums =====//
|
||||
['type' => 'album'],
|
||||
[
|
||||
'query' => [
|
||||
'multi_match' => [
|
||||
'query' => $query,
|
||||
'fields' => [
|
||||
'title^2',
|
||||
'artist',
|
||||
'tracks',
|
||||
],
|
||||
'tie_breaker' => 0.3,
|
||||
],
|
||||
],
|
||||
'size' => 3
|
||||
],
|
||||
|
||||
//===== Playlists =====//
|
||||
['type' => 'playlist'],
|
||||
[
|
||||
'query' => [
|
||||
'multi_match' => [
|
||||
'query' => $query,
|
||||
'fields' => [
|
||||
'title^3',
|
||||
'curator',
|
||||
'tracks^2',
|
||||
],
|
||||
'tie_breaker' => 0.3,
|
||||
],
|
||||
],
|
||||
'size' => 3
|
||||
],
|
||||
|
||||
//===== Users =====//
|
||||
['type' => 'user'],
|
||||
[
|
||||
'query' => [
|
||||
'multi_match' => [
|
||||
'query' => $query,
|
||||
'fields' => [
|
||||
'display_name',
|
||||
'tracks',
|
||||
],
|
||||
'tie_breaker' => 0.3,
|
||||
],
|
||||
],
|
||||
'size' => 3
|
||||
],
|
||||
]
|
||||
]);
|
||||
|
||||
$tracks = $this->transformTracks($results['responses'][0]['hits']['hits']);
|
||||
$albums = $this->transformAlbums($results['responses'][1]['hits']['hits']);
|
||||
$playlists = $this->transformPlaylists($results['responses'][2]['hits']['hits']);
|
||||
$users = $this->transformUsers($results['responses'][3]['hits']['hits']);
|
||||
|
||||
return [
|
||||
'tracks' => $tracks,
|
||||
'albums' => $albums,
|
||||
'playlists' => $playlists,
|
||||
'users' => $users
|
||||
];
|
||||
}
|
||||
|
||||
protected function transformTracks(array $searchHits) {
|
||||
$tracks = $this->transformToEloquent(Track::class, $searchHits);
|
||||
$tracks = $tracks->map(function (Track $track) {
|
||||
return Track::mapPublicTrackSummary($track);
|
||||
});
|
||||
return $tracks;
|
||||
}
|
||||
|
||||
protected function transformAlbums(array $searchHits) {
|
||||
$albums = $this->transformToEloquent(Album::class, $searchHits);
|
||||
$albums = $albums->map(function (Album $album) {
|
||||
return Album::mapPublicAlbumSummary($album);
|
||||
});
|
||||
return $albums;
|
||||
}
|
||||
|
||||
protected function transformPlaylists(array $searchHits) {
|
||||
$playlists = $this->transformToEloquent(Playlist::class, $searchHits);
|
||||
$playlists = $playlists->map(function (Playlist $playlist) {
|
||||
return Playlist::mapPublicPlaylistSummary($playlist);
|
||||
});
|
||||
return $playlists;
|
||||
}
|
||||
|
||||
protected function transformUsers(array $searchHits) {
|
||||
$users = $this->transformToEloquent(User::class, $searchHits);
|
||||
$users = $users->map(function (User $user) {
|
||||
return User::mapPublicUserSummary($user);
|
||||
});
|
||||
return $users;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the given Elasticsearch results into a collection of corresponding
|
||||
* Eloquent models.
|
||||
*
|
||||
* This method assumes that the given class uses soft deletes.
|
||||
*
|
||||
* @param string $modelClass The Eloquent model class to instantiate these results as
|
||||
* @param array $searchHits
|
||||
* @return \Illuminate\Database\Eloquent\Collection
|
||||
*/
|
||||
protected function transformToEloquent(string $modelClass, array $searchHits) {
|
||||
if (empty($searchHits)) {
|
||||
return new Collection();
|
||||
}
|
||||
|
||||
$ids = [];
|
||||
$caseStatement = 'CASE id ';
|
||||
|
||||
$i = 0;
|
||||
foreach ($searchHits as $result) {
|
||||
$ids[$result['_id']] = $result['_score'];
|
||||
$caseStatement .= "WHEN ${result['_id']} THEN $i ";
|
||||
$i++;
|
||||
}
|
||||
$caseStatement .= 'END';
|
||||
|
||||
/** @var Builder $modelInstances */
|
||||
$modelInstances = $modelClass::query();
|
||||
|
||||
if (method_exists($modelClass, 'withTrashed')) {
|
||||
$modelInstances = $modelInstances->withTrashed();
|
||||
}
|
||||
|
||||
$modelInstances = $modelInstances
|
||||
->whereIn('id', array_keys($ids))
|
||||
->orderBy(DB::raw($caseStatement))
|
||||
->get();
|
||||
|
||||
return $modelInstances;
|
||||
}
|
||||
}
|
|
@ -27,7 +27,9 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
|||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Auth;
|
||||
use Cache;
|
||||
use Poniverse\Ponyfm\Contracts\Searchable;
|
||||
use Poniverse\Ponyfm\Exceptions\TrackFileNotFoundException;
|
||||
use Poniverse\Ponyfm\Traits\IndexedInElasticsearchTrait;
|
||||
use Poniverse\Ponyfm\Traits\TrackCollection;
|
||||
use Poniverse\Ponyfm\Traits\SlugTrait;
|
||||
use Venturecraft\Revisionable\RevisionableTrait;
|
||||
|
@ -59,9 +61,11 @@ use Venturecraft\Revisionable\RevisionableTrait;
|
|||
* @property-read \Illuminate\Database\Eloquent\Collection|\Venturecraft\Revisionable\Revision[] $revisionHistory
|
||||
* @method static \Illuminate\Database\Query\Builder|\Poniverse\Ponyfm\Models\Album userDetails()
|
||||
*/
|
||||
class Album extends Model
|
||||
class Album extends Model implements Searchable
|
||||
{
|
||||
use SoftDeletes, SlugTrait, DispatchesJobs, TrackCollection, RevisionableTrait;
|
||||
use SoftDeletes, SlugTrait, TrackCollection, RevisionableTrait, IndexedInElasticsearchTrait;
|
||||
|
||||
protected $elasticsearchType = 'album';
|
||||
|
||||
protected $dates = ['deleted_at'];
|
||||
protected $fillable = ['user_id', 'title', 'slug'];
|
||||
|
@ -403,4 +407,25 @@ class Album extends Model
|
|||
protected function recountTracks() {
|
||||
$this->track_count = $this->tracks->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this model in Elasticsearch-friendly form. The array returned by
|
||||
* this method should match the current mapping for this model's ES type.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toElasticsearch():array {
|
||||
return [
|
||||
'title' => $this->title,
|
||||
'artist' => $this->user->display_name,
|
||||
'tracks' => $this->tracks->pluck('title'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function shouldBeIndexed():bool {
|
||||
return $this->track_count > 0 && !$this->trashed();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,9 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
|||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Auth;
|
||||
use Cache;
|
||||
use Poniverse\Ponyfm\Contracts\Searchable;
|
||||
use Poniverse\Ponyfm\Exceptions\TrackFileNotFoundException;
|
||||
use Poniverse\Ponyfm\Traits\IndexedInElasticsearchTrait;
|
||||
use Poniverse\Ponyfm\Traits\TrackCollection;
|
||||
use Poniverse\Ponyfm\Traits\SlugTrait;
|
||||
use Venturecraft\Revisionable\RevisionableTrait;
|
||||
|
@ -58,13 +60,27 @@ use Venturecraft\Revisionable\RevisionableTrait;
|
|||
* @property-read \Illuminate\Database\Eloquent\Collection|\Venturecraft\Revisionable\Revision[] $revisionHistory
|
||||
* @method static \Illuminate\Database\Query\Builder|\Poniverse\Ponyfm\Models\Playlist userDetails()
|
||||
*/
|
||||
class Playlist extends Model
|
||||
class Playlist extends Model implements Searchable
|
||||
{
|
||||
use SoftDeletes, SlugTrait, DispatchesJobs, TrackCollection, RevisionableTrait;
|
||||
use SoftDeletes, SlugTrait, TrackCollection, RevisionableTrait, IndexedInElasticsearchTrait;
|
||||
|
||||
protected $elasticsearchType = 'playlist';
|
||||
|
||||
protected $table = 'playlists';
|
||||
|
||||
protected $dates = ['deleted_at'];
|
||||
protected $casts = [
|
||||
'id' => 'integer',
|
||||
'user_id' => 'integer',
|
||||
'title' => 'string',
|
||||
'description' => 'string',
|
||||
'is_public' => 'boolean',
|
||||
'track_count' => 'integer',
|
||||
'view_count' => 'integer',
|
||||
'download_count' => 'integer',
|
||||
'favourte_count' => 'integer',
|
||||
'follow_count' => 'integer',
|
||||
'comment_count' => 'integer',
|
||||
];
|
||||
|
||||
public static function summary()
|
||||
{
|
||||
|
@ -285,4 +301,27 @@ class Playlist extends Model
|
|||
{
|
||||
return 'playlist-' . $this->id . '-' . $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this model in Elasticsearch-friendly form. The array returned by
|
||||
* this method should match the current mapping for this model's ES type.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toElasticsearch():array {
|
||||
return [
|
||||
'title' => $this->title,
|
||||
'curator' => $this->user->display_name,
|
||||
'tracks' => $this->tracks->pluck('title'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function shouldBeIndexed():bool {
|
||||
return $this->is_public &&
|
||||
$this->track_count > 0 &&
|
||||
!$this->trashed();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,10 @@ use Auth;
|
|||
use Cache;
|
||||
use Config;
|
||||
use DB;
|
||||
use Elasticsearch;
|
||||
use Poniverse\Ponyfm\Contracts\Searchable;
|
||||
use Poniverse\Ponyfm\Exceptions\TrackFileNotFoundException;
|
||||
use Poniverse\Ponyfm\Traits\IndexedInElasticsearchTrait;
|
||||
use Poniverse\Ponyfm\Traits\SlugTrait;
|
||||
use Exception;
|
||||
use External;
|
||||
|
@ -93,9 +96,11 @@ use Venturecraft\Revisionable\RevisionableTrait;
|
|||
* @method static \Illuminate\Database\Query\Builder|\Poniverse\Ponyfm\Models\Track withComments()
|
||||
* @method static \Illuminate\Database\Query\Builder|\Poniverse\Ponyfm\Models\Track mlpma()
|
||||
*/
|
||||
class Track extends Model
|
||||
class Track extends Model implements Searchable
|
||||
{
|
||||
use SoftDeletes;
|
||||
use SoftDeletes, IndexedInElasticsearchTrait;
|
||||
|
||||
protected $elasticsearchType = 'track';
|
||||
|
||||
protected $dates = ['deleted_at', 'published_at', 'released_at'];
|
||||
protected $hidden = ['original_tags', 'metadata'];
|
||||
|
@ -826,4 +831,28 @@ class Track extends Model
|
|||
{
|
||||
return 'track-' . $this->id . '-' . $key;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function shouldBeIndexed():bool {
|
||||
return $this->is_listed &&
|
||||
$this->published_at !== null &&
|
||||
!$this->trashed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function toElasticsearch():array {
|
||||
return [
|
||||
'title' => $this->title,
|
||||
'artist' => $this->user->display_name,
|
||||
'published_at' => $this->published_at ? $this->published_at->toIso8601String() : null,
|
||||
'genre' => $this->genre->name,
|
||||
'track_type' => $this->trackType->title,
|
||||
'show_songs' => $this->showSongs->pluck('title')
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,8 @@ use Illuminate\Database\Eloquent\Model;
|
|||
use Illuminate\Foundation\Auth\Access\Authorizable;
|
||||
use Auth;
|
||||
use Illuminate\Support\Str;
|
||||
use Poniverse\Ponyfm\Contracts\Searchable;
|
||||
use Poniverse\Ponyfm\Traits\IndexedInElasticsearchTrait;
|
||||
use Venturecraft\Revisionable\RevisionableTrait;
|
||||
|
||||
/**
|
||||
|
@ -62,9 +64,11 @@ use Venturecraft\Revisionable\RevisionableTrait;
|
|||
* @property-read \Illuminate\Database\Eloquent\Collection|\Venturecraft\Revisionable\Revision[] $revisionHistory
|
||||
* @method static \Illuminate\Database\Query\Builder|\Poniverse\Ponyfm\Models\User userDetails()
|
||||
*/
|
||||
class User extends Model implements AuthenticatableContract, CanResetPasswordContract, \Illuminate\Contracts\Auth\Access\Authorizable
|
||||
class User extends Model implements AuthenticatableContract, CanResetPasswordContract, \Illuminate\Contracts\Auth\Access\Authorizable, Searchable
|
||||
{
|
||||
use Authenticatable, CanResetPassword, Authorizable, RevisionableTrait;
|
||||
use Authenticatable, CanResetPassword, Authorizable, RevisionableTrait, IndexedInElasticsearchTrait;
|
||||
|
||||
protected $elasticsearchType = 'user';
|
||||
|
||||
protected $table = 'users';
|
||||
protected $casts = [
|
||||
|
@ -247,4 +251,40 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function mapPublicUserSummary(User $user) {
|
||||
return [
|
||||
'id' => $user->id,
|
||||
'name' => $user->display_name,
|
||||
'slug' => $user->slug,
|
||||
'url' => $user->url,
|
||||
'is_archived' => $user->is_archived,
|
||||
'avatars' => [
|
||||
'small' => $user->getAvatarUrl(Image::SMALL),
|
||||
'normal' => $user->getAvatarUrl(Image::NORMAL)
|
||||
],
|
||||
'created_at' => $user->created_at
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this model in Elasticsearch-friendly form. The array returned by
|
||||
* this method should match the current mapping for this model's ES type.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toElasticsearch():array {
|
||||
return [
|
||||
'username' => $this->username,
|
||||
'display_name' => $this->display_name,
|
||||
'tracks' => $this->tracks->pluck('title'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function shouldBeIndexed():bool {
|
||||
return $this->disabled_at === null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
|
||||
namespace Poniverse\Ponyfm\Providers;
|
||||
|
||||
use DB;
|
||||
use Illuminate\Database\SQLiteConnection;
|
||||
use Illuminate\Foundation\Application;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use PfmValidator;
|
||||
|
@ -53,5 +51,12 @@ class AppServiceProvider extends ServiceProvider
|
|||
$this->app->bind(Poniverse::class, function(Application $app) {
|
||||
return new Poniverse($app['config']->get('poniverse.client_id'), $app['config']->get('poniverse.secret'));
|
||||
});
|
||||
|
||||
$this->app->bind(Poniverse\Ponyfm\Library\Search::class, function(Application $app) {
|
||||
return new Poniverse\Ponyfm\Library\Search(
|
||||
\Elasticsearch::connection(),
|
||||
$app['config']->get('ponyfm.elasticsearch_index')
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,6 +48,10 @@ class AuthServiceProvider extends ServiceProvider
|
|||
*/
|
||||
public function boot(GateContract $gate)
|
||||
{
|
||||
$gate->define('access-search', function(User $user) {
|
||||
return $user->hasRole('admin') || $user->hasRole('moderator');
|
||||
});
|
||||
|
||||
$gate->define('access-admin-area', function(User $user) {
|
||||
return $user->hasRole('admin');
|
||||
});
|
||||
|
|
111
app/Traits/IndexedInElasticsearchTrait.php
Normal file
111
app/Traits/IndexedInElasticsearchTrait.php
Normal file
|
@ -0,0 +1,111 @@
|
|||
<?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/>.
|
||||
*/
|
||||
|
||||
namespace Poniverse\Ponyfm\Traits;
|
||||
|
||||
use Config;
|
||||
use Elasticsearch;
|
||||
use Elasticsearch\Common\Exceptions\Missing404Exception;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Poniverse\Ponyfm\Contracts\Searchable;
|
||||
use Poniverse\Ponyfm\Jobs\UpdateSearchIndexForEntity;
|
||||
|
||||
/**
|
||||
* Class IndexedInElasticsearch
|
||||
*
|
||||
* Classes using this trait must declare the `$elasticsearchType` property and
|
||||
* implement the `Searchable` interface.
|
||||
*
|
||||
* @package Poniverse\Ponyfm\Traits
|
||||
*/
|
||||
trait IndexedInElasticsearchTrait
|
||||
{
|
||||
use DispatchesJobs;
|
||||
|
||||
// These two functions are from the Searchable interface. They're included
|
||||
// here, without being implemented, to assist IDE's when editing this trait.
|
||||
public abstract function toElasticsearch():array;
|
||||
public abstract function shouldBeIndexed():bool;
|
||||
|
||||
|
||||
// Laravel automatically runs this method based on the trait's name. #magic
|
||||
public static function bootIndexedInElasticsearchTrait() {
|
||||
static::saved(function (Searchable $entity) {
|
||||
$entity->updateElasticsearchEntry();
|
||||
});
|
||||
|
||||
static::deleted(function (Searchable $entity) {
|
||||
$entity->updateElasticsearchEntry();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $includeBody set to false when deleting documents
|
||||
* @return array
|
||||
*/
|
||||
private function getElasticsearchParameters(bool $includeBody = true) {
|
||||
$parameters = [
|
||||
'index' => Config::get('ponyfm.elasticsearch_index'),
|
||||
'type' => $this->elasticsearchType,
|
||||
'id' => $this->id,
|
||||
];
|
||||
|
||||
if ($includeBody) {
|
||||
$parameters['body'] = $this->toElasticsearch();
|
||||
}
|
||||
|
||||
return $parameters;
|
||||
}
|
||||
|
||||
private function createOrUpdateElasticsearchEntry() {
|
||||
Elasticsearch::connection()->index($this->getElasticsearchParameters());
|
||||
}
|
||||
|
||||
private function deleteElasticsearchEntry() {
|
||||
try {
|
||||
Elasticsearch::connection()->delete($this->getElasticsearchParameters(false));
|
||||
|
||||
} catch (Missing404Exception $e) {
|
||||
// If the entity we're trying to delete isn't indexed in Elasticsearch,
|
||||
// that's fine.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously updates the Elasticsearch entry.
|
||||
* When in doubt, this is the method to use.
|
||||
*/
|
||||
public function updateElasticsearchEntry() {
|
||||
$job = (new UpdateSearchIndexForEntity($this))->onQueue(Config::get('ponyfm.indexing_queue'));
|
||||
$this->dispatch($job);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronously updates the Elasticsearch entry. This should only be
|
||||
* called from the UpdateSearchIndexForEntity job.
|
||||
*/
|
||||
public function updateElasticsearchEntrySynchronously() {
|
||||
if ($this->shouldBeIndexed()) {
|
||||
$this->createOrUpdateElasticsearchEntry();
|
||||
} else {
|
||||
$this->deleteElasticsearchEntry();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,7 +13,8 @@
|
|||
"guzzlehttp/guzzle": "~6.0",
|
||||
"doctrine/dbal": "^2.5",
|
||||
"venturecraft/revisionable": "^1.23",
|
||||
"pda/pheanstalk": "~3.0"
|
||||
"pda/pheanstalk": "~3.0",
|
||||
"cviebrock/laravel-elasticsearch": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"fzaninotto/faker": "~1.4",
|
||||
|
|
492
composer.lock
generated
492
composer.lock
generated
|
@ -4,8 +4,8 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"hash": "d99fa4165b8a1c9e929248bbb16183ad",
|
||||
"content-hash": "31347c82515003f78f1f9adef010f1f5",
|
||||
"hash": "0deb7713636ee82aadee47da3a9217cc",
|
||||
"content-hash": "9dea148233d815e53eb636413f2bcaed",
|
||||
"packages": [
|
||||
{
|
||||
"name": "barryvdh/laravel-ide-helper",
|
||||
|
@ -168,6 +168,55 @@
|
|||
],
|
||||
"time": "2013-05-05 09:10:04"
|
||||
},
|
||||
{
|
||||
"name": "cviebrock/laravel-elasticsearch",
|
||||
"version": "1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/cviebrock/laravel-elasticsearch.git",
|
||||
"reference": "52aa1f8228006cb0bb60954e26c068af523bf47b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/cviebrock/laravel-elasticsearch/zipball/52aa1f8228006cb0bb60954e26c068af523bf47b",
|
||||
"reference": "52aa1f8228006cb0bb60954e26c068af523bf47b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"elasticsearch/elasticsearch": "^2.0",
|
||||
"illuminate/support": "~4|~5",
|
||||
"monolog/monolog": "~1",
|
||||
"php": ">=5.4.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Cviebrock\\LaravelElasticsearch\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Colin Viebrock",
|
||||
"email": "colin@viebrock.ca"
|
||||
},
|
||||
{
|
||||
"name": "Brandon Martel",
|
||||
"email": "brandonmartel@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "An easy way to use the official PHP ElasticSearch client in your Laravel applications",
|
||||
"keywords": [
|
||||
"client",
|
||||
"elasticsearch",
|
||||
"laravel",
|
||||
"search"
|
||||
],
|
||||
"time": "2016-01-06 15:58:07"
|
||||
},
|
||||
{
|
||||
"name": "danielstjules/stringy",
|
||||
"version": "1.10.0",
|
||||
|
@ -327,33 +376,33 @@
|
|||
},
|
||||
{
|
||||
"name": "doctrine/cache",
|
||||
"version": "v1.5.4",
|
||||
"version": "v1.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/cache.git",
|
||||
"reference": "47cdc76ceb95cc591d9c79a36dc3794975b5d136"
|
||||
"reference": "f8af318d14bdb0eff0336795b428b547bd39ccb6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/cache/zipball/47cdc76ceb95cc591d9c79a36dc3794975b5d136",
|
||||
"reference": "47cdc76ceb95cc591d9c79a36dc3794975b5d136",
|
||||
"url": "https://api.github.com/repos/doctrine/cache/zipball/f8af318d14bdb0eff0336795b428b547bd39ccb6",
|
||||
"reference": "f8af318d14bdb0eff0336795b428b547bd39ccb6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.2"
|
||||
"php": "~5.5|~7.0"
|
||||
},
|
||||
"conflict": {
|
||||
"doctrine/common": ">2.2,<2.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": ">=3.7",
|
||||
"phpunit/phpunit": "~4.8|~5.0",
|
||||
"predis/predis": "~1.0",
|
||||
"satooshi/php-coveralls": "~0.6"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.5.x-dev"
|
||||
"dev-master": "1.6.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -393,7 +442,7 @@
|
|||
"cache",
|
||||
"caching"
|
||||
],
|
||||
"time": "2015-12-19 05:03:47"
|
||||
"time": "2015-12-31 16:37:02"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/collections",
|
||||
|
@ -463,16 +512,16 @@
|
|||
},
|
||||
{
|
||||
"name": "doctrine/common",
|
||||
"version": "v2.5.2",
|
||||
"version": "v2.6.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/common.git",
|
||||
"reference": "311001fd9865a4d0d59efff4eac6d7dcb3f5270c"
|
||||
"reference": "a579557bc689580c19fee4e27487a67fe60defc0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/common/zipball/311001fd9865a4d0d59efff4eac6d7dcb3f5270c",
|
||||
"reference": "311001fd9865a4d0d59efff4eac6d7dcb3f5270c",
|
||||
"url": "https://api.github.com/repos/doctrine/common/zipball/a579557bc689580c19fee4e27487a67fe60defc0",
|
||||
"reference": "a579557bc689580c19fee4e27487a67fe60defc0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -481,20 +530,20 @@
|
|||
"doctrine/collections": "1.*",
|
||||
"doctrine/inflector": "1.*",
|
||||
"doctrine/lexer": "1.*",
|
||||
"php": ">=5.3.2"
|
||||
"php": "~5.5|~7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~3.7"
|
||||
"phpunit/phpunit": "~4.8|~5.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.5.x-dev"
|
||||
"dev-master": "2.7.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Doctrine\\Common\\": "lib/"
|
||||
"psr-4": {
|
||||
"Doctrine\\Common\\": "lib/Doctrine/Common"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
|
@ -532,24 +581,24 @@
|
|||
"persistence",
|
||||
"spl"
|
||||
],
|
||||
"time": "2015-12-04 12:49:42"
|
||||
"time": "2015-12-25 13:18:31"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/dbal",
|
||||
"version": "v2.5.2",
|
||||
"version": "v2.5.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/dbal.git",
|
||||
"reference": "01dbcbc5cd0a913d751418e635434a18a2f2a75c"
|
||||
"reference": "abbdfd1cff43a7b99d027af3be709bc8fc7d4769"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/dbal/zipball/01dbcbc5cd0a913d751418e635434a18a2f2a75c",
|
||||
"reference": "01dbcbc5cd0a913d751418e635434a18a2f2a75c",
|
||||
"url": "https://api.github.com/repos/doctrine/dbal/zipball/abbdfd1cff43a7b99d027af3be709bc8fc7d4769",
|
||||
"reference": "abbdfd1cff43a7b99d027af3be709bc8fc7d4769",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/common": ">=2.4,<2.6-dev",
|
||||
"doctrine/common": ">=2.4,<2.7-dev",
|
||||
"php": ">=5.3.2"
|
||||
},
|
||||
"require-dev": {
|
||||
|
@ -603,7 +652,7 @@
|
|||
"persistence",
|
||||
"queryobject"
|
||||
],
|
||||
"time": "2015-09-16 16:29:33"
|
||||
"time": "2016-01-05 22:11:12"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/inflector",
|
||||
|
@ -726,6 +775,60 @@
|
|||
],
|
||||
"time": "2014-09-09 13:34:57"
|
||||
},
|
||||
{
|
||||
"name": "elasticsearch/elasticsearch",
|
||||
"version": "v2.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/elastic/elasticsearch-php.git",
|
||||
"reference": "9ce5bd7606f6c185d434de4f80863f998f74e179"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/elastic/elasticsearch-php/zipball/9ce5bd7606f6c185d434de4f80863f998f74e179",
|
||||
"reference": "9ce5bd7606f6c185d434de4f80863f998f74e179",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"guzzlehttp/ringphp": "~1.0",
|
||||
"php": ">=5.4",
|
||||
"psr/log": "~1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"athletic/athletic": "~0.1",
|
||||
"cpliakas/git-wrapper": "~1.0",
|
||||
"mockery/mockery": "dev-master@dev",
|
||||
"phpunit/phpunit": "3.7.*",
|
||||
"symfony/yaml": "2.4.3 as 2.4.2",
|
||||
"twig/twig": "1.*"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-curl": "*",
|
||||
"monolog/monolog": "Allows for client-level logging and tracing"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Elasticsearch\\": "src/Elasticsearch/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"Apache 2"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Zachary Tong"
|
||||
}
|
||||
],
|
||||
"description": "PHP Client for Elasticsearch",
|
||||
"keywords": [
|
||||
"client",
|
||||
"elasticsearch",
|
||||
"search"
|
||||
],
|
||||
"time": "2015-11-05 15:29:21"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/guzzle",
|
||||
"version": "6.1.1",
|
||||
|
@ -897,6 +1000,107 @@
|
|||
],
|
||||
"time": "2015-11-03 01:34:55"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/ringphp",
|
||||
"version": "1.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/guzzle/RingPHP.git",
|
||||
"reference": "dbbb91d7f6c191e5e405e900e3102ac7f261bc0b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/guzzle/RingPHP/zipball/dbbb91d7f6c191e5e405e900e3102ac7f261bc0b",
|
||||
"reference": "dbbb91d7f6c191e5e405e900e3102ac7f261bc0b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"guzzlehttp/streams": "~3.0",
|
||||
"php": ">=5.4.0",
|
||||
"react/promise": "~2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-curl": "*",
|
||||
"phpunit/phpunit": "~4.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-curl": "Guzzle will use specific adapters if cURL is present"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.1-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"GuzzleHttp\\Ring\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Michael Dowling",
|
||||
"email": "mtdowling@gmail.com",
|
||||
"homepage": "https://github.com/mtdowling"
|
||||
}
|
||||
],
|
||||
"description": "Provides a simple API and specification that abstracts away the details of HTTP into a single PHP function.",
|
||||
"time": "2015-05-20 03:37:09"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/streams",
|
||||
"version": "3.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/guzzle/streams.git",
|
||||
"reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/guzzle/streams/zipball/47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5",
|
||||
"reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"GuzzleHttp\\Stream\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Michael Dowling",
|
||||
"email": "mtdowling@gmail.com",
|
||||
"homepage": "https://github.com/mtdowling"
|
||||
}
|
||||
],
|
||||
"description": "Provides a simple abstraction over streams of data",
|
||||
"homepage": "http://guzzlephp.org/",
|
||||
"keywords": [
|
||||
"Guzzle",
|
||||
"stream"
|
||||
],
|
||||
"time": "2014-10-12 19:18:40"
|
||||
},
|
||||
{
|
||||
"name": "intouch/laravel-newrelic",
|
||||
"version": "2.0.0",
|
||||
|
@ -1129,16 +1333,16 @@
|
|||
},
|
||||
{
|
||||
"name": "laravel/framework",
|
||||
"version": "v5.1.27",
|
||||
"version": "v5.1.28",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/framework.git",
|
||||
"reference": "b16f80878fd3603022d3c84593397cedd9af0bcf"
|
||||
"reference": "3f0fd27939dfdafb1e50058423cd24e640894ba2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/b16f80878fd3603022d3c84593397cedd9af0bcf",
|
||||
"reference": "b16f80878fd3603022d3c84593397cedd9af0bcf",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/3f0fd27939dfdafb1e50058423cd24e640894ba2",
|
||||
"reference": "3f0fd27939dfdafb1e50058423cd24e640894ba2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1253,7 +1457,7 @@
|
|||
"framework",
|
||||
"laravel"
|
||||
],
|
||||
"time": "2015-12-17 20:35:38"
|
||||
"time": "2015-12-31 17:41:30"
|
||||
},
|
||||
{
|
||||
"name": "league/flysystem",
|
||||
|
@ -1560,16 +1764,16 @@
|
|||
},
|
||||
{
|
||||
"name": "paragonie/random_compat",
|
||||
"version": "1.1.4",
|
||||
"version": "1.1.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/paragonie/random_compat.git",
|
||||
"reference": "d762ee5b099a29044603cd4649851e81aa66cb47"
|
||||
"reference": "dd8998b7c846f6909f4e7a5f67fabebfc412a4f7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/d762ee5b099a29044603cd4649851e81aa66cb47",
|
||||
"reference": "d762ee5b099a29044603cd4649851e81aa66cb47",
|
||||
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/dd8998b7c846f6909f4e7a5f67fabebfc412a4f7",
|
||||
"reference": "dd8998b7c846f6909f4e7a5f67fabebfc412a4f7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1604,7 +1808,7 @@
|
|||
"pseudorandom",
|
||||
"random"
|
||||
],
|
||||
"time": "2015-12-10 14:48:13"
|
||||
"time": "2016-01-06 13:31:20"
|
||||
},
|
||||
{
|
||||
"name": "pda/pheanstalk",
|
||||
|
@ -1864,6 +2068,50 @@
|
|||
],
|
||||
"time": "2015-11-12 16:18:56"
|
||||
},
|
||||
{
|
||||
"name": "react/promise",
|
||||
"version": "v2.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/reactphp/promise.git",
|
||||
"reference": "3b6fca09c7d56321057fa8867c8dbe1abf648627"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/reactphp/promise/zipball/3b6fca09c7d56321057fa8867c8dbe1abf648627",
|
||||
"reference": "3b6fca09c7d56321057fa8867c8dbe1abf648627",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.4.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"React\\Promise\\": "src/"
|
||||
},
|
||||
"files": [
|
||||
"src/functions_include.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jan Sorgalla",
|
||||
"email": "jsorgalla@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "A lightweight implementation of CommonJS Promises/A for PHP",
|
||||
"time": "2015-07-03 13:48:55"
|
||||
},
|
||||
{
|
||||
"name": "swiftmailer/swiftmailer",
|
||||
"version": "v5.4.1",
|
||||
|
@ -1919,16 +2167,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/class-loader",
|
||||
"version": "v2.8.0",
|
||||
"version": "v2.8.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/class-loader.git",
|
||||
"reference": "51f83451bf0ddfc696e47e4642d6cd10fcfce160"
|
||||
"reference": "98e9089a428ed0e39423b67352c57ef5910a3269"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/class-loader/zipball/51f83451bf0ddfc696e47e4642d6cd10fcfce160",
|
||||
"reference": "51f83451bf0ddfc696e47e4642d6cd10fcfce160",
|
||||
"url": "https://api.github.com/repos/symfony/class-loader/zipball/98e9089a428ed0e39423b67352c57ef5910a3269",
|
||||
"reference": "98e9089a428ed0e39423b67352c57ef5910a3269",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1967,20 +2215,20 @@
|
|||
],
|
||||
"description": "Symfony ClassLoader Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-11-26 07:00:59"
|
||||
"time": "2016-01-03 15:33:41"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v2.7.7",
|
||||
"version": "v2.7.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "16bb1cb86df43c90931df65f529e7ebd79636750"
|
||||
"reference": "d3fc138b6ed8f8074591821d3416d8f9c04d6ca6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/16bb1cb86df43c90931df65f529e7ebd79636750",
|
||||
"reference": "16bb1cb86df43c90931df65f529e7ebd79636750",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/d3fc138b6ed8f8074591821d3416d8f9c04d6ca6",
|
||||
"reference": "d3fc138b6ed8f8074591821d3416d8f9c04d6ca6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2026,20 +2274,20 @@
|
|||
],
|
||||
"description": "Symfony Console Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-11-18 09:54:26"
|
||||
"time": "2016-01-14 08:26:43"
|
||||
},
|
||||
{
|
||||
"name": "symfony/css-selector",
|
||||
"version": "v2.7.7",
|
||||
"version": "v2.7.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/css-selector.git",
|
||||
"reference": "abb47717fb88aebd9437da2fc8bb01a50a36679f"
|
||||
"reference": "1a869e59cc3b2802961fc2124139659e12b72fe5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/css-selector/zipball/abb47717fb88aebd9437da2fc8bb01a50a36679f",
|
||||
"reference": "abb47717fb88aebd9437da2fc8bb01a50a36679f",
|
||||
"url": "https://api.github.com/repos/symfony/css-selector/zipball/1a869e59cc3b2802961fc2124139659e12b72fe5",
|
||||
"reference": "1a869e59cc3b2802961fc2124139659e12b72fe5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2079,20 +2327,20 @@
|
|||
],
|
||||
"description": "Symfony CssSelector Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-10-30 20:10:21"
|
||||
"time": "2016-01-03 15:32:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/debug",
|
||||
"version": "v2.7.7",
|
||||
"version": "v2.7.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/debug.git",
|
||||
"reference": "0dbc119596f4afc82d9b2eb2a7e6a4af1ee763fa"
|
||||
"reference": "5aca4aa9600b943287b4a1799a4d1d78b5388175"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/debug/zipball/0dbc119596f4afc82d9b2eb2a7e6a4af1ee763fa",
|
||||
"reference": "0dbc119596f4afc82d9b2eb2a7e6a4af1ee763fa",
|
||||
"url": "https://api.github.com/repos/symfony/debug/zipball/5aca4aa9600b943287b4a1799a4d1d78b5388175",
|
||||
"reference": "5aca4aa9600b943287b4a1799a4d1d78b5388175",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2136,20 +2384,20 @@
|
|||
],
|
||||
"description": "Symfony Debug Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-10-30 20:10:21"
|
||||
"time": "2016-01-13 07:57:33"
|
||||
},
|
||||
{
|
||||
"name": "symfony/dom-crawler",
|
||||
"version": "v2.7.7",
|
||||
"version": "v2.7.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/dom-crawler.git",
|
||||
"reference": "b33593cbfe1d81b50d48353f338aca76a08658d8"
|
||||
"reference": "55cc79a177193eb3bd74ac54b353691fbb211d3a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/b33593cbfe1d81b50d48353f338aca76a08658d8",
|
||||
"reference": "b33593cbfe1d81b50d48353f338aca76a08658d8",
|
||||
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/55cc79a177193eb3bd74ac54b353691fbb211d3a",
|
||||
"reference": "55cc79a177193eb3bd74ac54b353691fbb211d3a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2191,20 +2439,20 @@
|
|||
],
|
||||
"description": "Symfony DomCrawler Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-11-02 20:20:53"
|
||||
"time": "2016-01-03 15:32:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/event-dispatcher",
|
||||
"version": "v2.8.0",
|
||||
"version": "v2.8.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/event-dispatcher.git",
|
||||
"reference": "a5eb815363c0388e83247e7e9853e5dbc14999cc"
|
||||
"reference": "ee278f7c851533e58ca307f66305ccb9188aceda"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/a5eb815363c0388e83247e7e9853e5dbc14999cc",
|
||||
"reference": "a5eb815363c0388e83247e7e9853e5dbc14999cc",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/ee278f7c851533e58ca307f66305ccb9188aceda",
|
||||
"reference": "ee278f7c851533e58ca307f66305ccb9188aceda",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2251,20 +2499,20 @@
|
|||
],
|
||||
"description": "Symfony EventDispatcher Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-10-30 20:15:42"
|
||||
"time": "2016-01-13 10:28:07"
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v2.7.7",
|
||||
"version": "v2.7.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "a06a0c0ff7db3736a50d530c908cca547bf13da9"
|
||||
"reference": "d20ac81c81a67ab898b0c0afa435f3e9a7d460cf"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/a06a0c0ff7db3736a50d530c908cca547bf13da9",
|
||||
"reference": "a06a0c0ff7db3736a50d530c908cca547bf13da9",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/d20ac81c81a67ab898b0c0afa435f3e9a7d460cf",
|
||||
"reference": "d20ac81c81a67ab898b0c0afa435f3e9a7d460cf",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2300,20 +2548,20 @@
|
|||
],
|
||||
"description": "Symfony Finder Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-10-30 20:10:21"
|
||||
"time": "2016-01-14 08:26:43"
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-foundation",
|
||||
"version": "v2.7.7",
|
||||
"version": "v2.7.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-foundation.git",
|
||||
"reference": "e83a3d105ddaf5a113e803c904fdec552d1f1c35"
|
||||
"reference": "2f9d240056f026af5f7ba7f7052b0c6709bf288c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/e83a3d105ddaf5a113e803c904fdec552d1f1c35",
|
||||
"reference": "e83a3d105ddaf5a113e803c904fdec552d1f1c35",
|
||||
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/2f9d240056f026af5f7ba7f7052b0c6709bf288c",
|
||||
"reference": "2f9d240056f026af5f7ba7f7052b0c6709bf288c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2355,20 +2603,20 @@
|
|||
],
|
||||
"description": "Symfony HttpFoundation Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-11-20 17:41:18"
|
||||
"time": "2016-01-13 10:26:43"
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-kernel",
|
||||
"version": "v2.7.7",
|
||||
"version": "v2.7.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-kernel.git",
|
||||
"reference": "5570de31e8fbc03777a8c61eb24f9b626e5e5941"
|
||||
"reference": "aa2f1e544d6cb862452504b5479a5095b7bfc53f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/5570de31e8fbc03777a8c61eb24f9b626e5e5941",
|
||||
"reference": "5570de31e8fbc03777a8c61eb24f9b626e5e5941",
|
||||
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/aa2f1e544d6cb862452504b5479a5095b7bfc53f",
|
||||
"reference": "aa2f1e544d6cb862452504b5479a5095b7bfc53f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2437,20 +2685,20 @@
|
|||
],
|
||||
"description": "Symfony HttpKernel Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-11-23 11:57:49"
|
||||
"time": "2016-01-14 10:41:45"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php56",
|
||||
"version": "v1.0.0",
|
||||
"version": "v1.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php56.git",
|
||||
"reference": "a6bd4770a6967517e6610529e14afaa3111094a3"
|
||||
"reference": "e2e77609a9e2328eb370fbb0e0d8b2000ebb488f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/a6bd4770a6967517e6610529e14afaa3111094a3",
|
||||
"reference": "a6bd4770a6967517e6610529e14afaa3111094a3",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/e2e77609a9e2328eb370fbb0e0d8b2000ebb488f",
|
||||
"reference": "e2e77609a9e2328eb370fbb0e0d8b2000ebb488f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2493,11 +2741,11 @@
|
|||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"time": "2015-11-04 20:28:58"
|
||||
"time": "2015-12-18 15:10:25"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-util",
|
||||
"version": "v1.0.0",
|
||||
"version": "v1.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-util.git",
|
||||
|
@ -2549,16 +2797,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
"version": "v2.7.7",
|
||||
"version": "v2.7.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/process.git",
|
||||
"reference": "f6290983c8725d0afa29bdc3e5295879de3e58f5"
|
||||
"reference": "0570b9ca51135ee7da0f19239eaf7b07ffb87034"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/f6290983c8725d0afa29bdc3e5295879de3e58f5",
|
||||
"reference": "f6290983c8725d0afa29bdc3e5295879de3e58f5",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/0570b9ca51135ee7da0f19239eaf7b07ffb87034",
|
||||
"reference": "0570b9ca51135ee7da0f19239eaf7b07ffb87034",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2594,20 +2842,20 @@
|
|||
],
|
||||
"description": "Symfony Process Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-11-19 16:11:24"
|
||||
"time": "2016-01-06 09:57:37"
|
||||
},
|
||||
{
|
||||
"name": "symfony/routing",
|
||||
"version": "v2.7.7",
|
||||
"version": "v2.7.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/routing.git",
|
||||
"reference": "7450f6196711b124fb8b04a12286d01a0401ddfe"
|
||||
"reference": "6fec77993acfe19aecf60544b9c7d32f3d5b2506"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/routing/zipball/7450f6196711b124fb8b04a12286d01a0401ddfe",
|
||||
"reference": "7450f6196711b124fb8b04a12286d01a0401ddfe",
|
||||
"url": "https://api.github.com/repos/symfony/routing/zipball/6fec77993acfe19aecf60544b9c7d32f3d5b2506",
|
||||
"reference": "6fec77993acfe19aecf60544b9c7d32f3d5b2506",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2667,20 +2915,20 @@
|
|||
"uri",
|
||||
"url"
|
||||
],
|
||||
"time": "2015-11-18 13:41:01"
|
||||
"time": "2016-01-03 15:32:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/translation",
|
||||
"version": "v2.7.7",
|
||||
"version": "v2.7.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/translation.git",
|
||||
"reference": "e4ecb9c3ba1304eaf24de15c2d7a428101c1982f"
|
||||
"reference": "8cbab8445ad4269427077ba02fff8718cb397e22"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/translation/zipball/e4ecb9c3ba1304eaf24de15c2d7a428101c1982f",
|
||||
"reference": "e4ecb9c3ba1304eaf24de15c2d7a428101c1982f",
|
||||
"url": "https://api.github.com/repos/symfony/translation/zipball/8cbab8445ad4269427077ba02fff8718cb397e22",
|
||||
"reference": "8cbab8445ad4269427077ba02fff8718cb397e22",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2730,20 +2978,20 @@
|
|||
],
|
||||
"description": "Symfony Translation Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-11-18 13:41:01"
|
||||
"time": "2016-01-03 15:32:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/var-dumper",
|
||||
"version": "v2.7.7",
|
||||
"version": "v2.7.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/var-dumper.git",
|
||||
"reference": "72bcb27411780eaee9469729aace73c0d46fb2b8"
|
||||
"reference": "ad39199e91f2f845a0181b14d459fda13a622138"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/72bcb27411780eaee9469729aace73c0d46fb2b8",
|
||||
"reference": "72bcb27411780eaee9469729aace73c0d46fb2b8",
|
||||
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/ad39199e91f2f845a0181b14d459fda13a622138",
|
||||
"reference": "ad39199e91f2f845a0181b14d459fda13a622138",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2789,20 +3037,20 @@
|
|||
"debug",
|
||||
"dump"
|
||||
],
|
||||
"time": "2015-11-18 13:41:01"
|
||||
"time": "2016-01-07 11:12:32"
|
||||
},
|
||||
{
|
||||
"name": "venturecraft/revisionable",
|
||||
"version": "1.24.0",
|
||||
"version": "1.26.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/VentureCraft/revisionable.git",
|
||||
"reference": "99c27d94f80ae9240cec89c4276f61e748e989a5"
|
||||
"reference": "7a3d5304de6c10d43cfb0d9ebe0bbdbb6e5b82ee"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/VentureCraft/revisionable/zipball/99c27d94f80ae9240cec89c4276f61e748e989a5",
|
||||
"reference": "99c27d94f80ae9240cec89c4276f61e748e989a5",
|
||||
"url": "https://api.github.com/repos/VentureCraft/revisionable/zipball/7a3d5304de6c10d43cfb0d9ebe0bbdbb6e5b82ee",
|
||||
"reference": "7a3d5304de6c10d43cfb0d9ebe0bbdbb6e5b82ee",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2837,7 +3085,7 @@
|
|||
"model",
|
||||
"revision"
|
||||
],
|
||||
"time": "2015-12-09 21:48:10"
|
||||
"time": "2016-01-13 12:14:05"
|
||||
},
|
||||
{
|
||||
"name": "vlucas/phpdotenv",
|
||||
|
@ -3139,16 +3387,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpspec/phpspec",
|
||||
"version": "2.4.0",
|
||||
"version": "2.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpspec/phpspec.git",
|
||||
"reference": "1d3938e6d9ffb1bd4805ea8ddac62ea48767f358"
|
||||
"reference": "5528ce1e93a1efa090c9404aba3395c329b4e6ed"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpspec/phpspec/zipball/1d3938e6d9ffb1bd4805ea8ddac62ea48767f358",
|
||||
"reference": "1d3938e6d9ffb1bd4805ea8ddac62ea48767f358",
|
||||
"url": "https://api.github.com/repos/phpspec/phpspec/zipball/5528ce1e93a1efa090c9404aba3395c329b4e6ed",
|
||||
"reference": "5528ce1e93a1efa090c9404aba3395c329b4e6ed",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -3213,7 +3461,7 @@
|
|||
"testing",
|
||||
"tests"
|
||||
],
|
||||
"time": "2015-11-29 02:03:49"
|
||||
"time": "2016-01-01 10:17:54"
|
||||
},
|
||||
{
|
||||
"name": "phpspec/prophecy",
|
||||
|
@ -4016,16 +4264,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v3.0.0",
|
||||
"version": "v3.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/yaml.git",
|
||||
"reference": "177a015cb0e19ff4a49e0e2e2c5fc1c1bee07002"
|
||||
"reference": "3df409958a646dad2bc5046c3fb671ee24a1a691"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/177a015cb0e19ff4a49e0e2e2c5fc1c1bee07002",
|
||||
"reference": "177a015cb0e19ff4a49e0e2e2c5fc1c1bee07002",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/3df409958a646dad2bc5046c3fb671ee24a1a691",
|
||||
"reference": "3df409958a646dad2bc5046c3fb671ee24a1a691",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -4061,7 +4309,7 @@
|
|||
],
|
||||
"description": "Symfony Yaml Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2015-11-30 12:36:17"
|
||||
"time": "2015-12-26 13:39:53"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
|
|
|
@ -147,6 +147,7 @@ return [
|
|||
|
||||
Intouch\LaravelNewrelic\NewrelicServiceProvider::class,
|
||||
Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class,
|
||||
Cviebrock\LaravelElasticsearch\ServiceProvider::class,
|
||||
|
||||
],
|
||||
|
||||
|
@ -197,6 +198,7 @@ return [
|
|||
'Validator' => Illuminate\Support\Facades\Validator::class,
|
||||
'View' => Illuminate\Support\Facades\View::class,
|
||||
|
||||
'Elasticsearch' => Cviebrock\LaravelElasticsearch\Facade::class,
|
||||
'Newrelic' => Intouch\LaravelNewrelic\Facades\Newrelic::class,
|
||||
|
||||
],
|
||||
|
|
168
config/elasticsearch.php
Normal file
168
config/elasticsearch.php
Normal file
|
@ -0,0 +1,168 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/**
|
||||
* You can specify one of several different connections when building an
|
||||
* Elasticsearch client.
|
||||
*
|
||||
* Here you may specify which of the connections below you wish to use
|
||||
* as your default connection when building an client. Of course you may
|
||||
* use create several clients at once, each with different configurations.
|
||||
*/
|
||||
|
||||
'defaultConnection' => 'default',
|
||||
|
||||
/**
|
||||
* These are the connection parameters used when building a client.
|
||||
*/
|
||||
|
||||
'connections' => [
|
||||
|
||||
'default' => [
|
||||
|
||||
/**
|
||||
* Hosts
|
||||
*
|
||||
* This is an array of hosts that the client will connect to. It can be a
|
||||
* single host name, or an array if you are running a cluster of Elasticsearch
|
||||
* instances.
|
||||
*
|
||||
* This is the only configuration value that is mandatory.
|
||||
*
|
||||
* If set in an environment variable, this should be a comma-separated
|
||||
* list of hostnames. Port numbers are optional; 9200 is the default.
|
||||
*
|
||||
* @see https://www.elastic.co/guide/en/elasticsearch/client/php-api/2.0/_configuration.html#_host_configuration
|
||||
*/
|
||||
|
||||
'hosts' => explode(',', env('ELASTICSEARCH_HOSTS', 'localhost:9200')),
|
||||
|
||||
/**
|
||||
* SSL
|
||||
*
|
||||
* If your Elasticsearch instance uses an out-dated or self-signed SSL
|
||||
* certificate, you will need to pass in the certificate bundle. This can
|
||||
* either be the path to the certificate file (for self-signed certs), or a
|
||||
* package like https://github.com/Kdyby/CurlCaBundle. See the documentation
|
||||
* below for all the details.
|
||||
*
|
||||
* If you are using SSL instances, and the certificates are up-to-date and
|
||||
* signed by a public certificate authority, then you can leave this null and
|
||||
* just use "https" in the host path(s) above and you should be fine.
|
||||
*
|
||||
* @see https://www.elastic.co/guide/en/elasticsearch/client/php-api/2.0/_security.html#_ssl_encryption_2
|
||||
*/
|
||||
|
||||
'sslVerification' => null,
|
||||
|
||||
/**
|
||||
* Logging
|
||||
*
|
||||
* Logging is handled by passing in an instance of Monolog\Logger (which
|
||||
* coincidentally is what Laravel's default logger is).
|
||||
*
|
||||
* If logging is enabled, you either need to set the path and log level
|
||||
* (some defaults are given for you below), or you can use a custom logger by
|
||||
* setting 'logObject' to an instance of Psr\Log\LoggerInterface. In fact,
|
||||
* if you just want to use the default Laravel logger, then set 'logObject'
|
||||
* to \Log::getMonolog().
|
||||
*
|
||||
* Note: 'logObject' takes precedent over 'logPath'/'logLevel', so set
|
||||
* 'logObject' null if you just want file-based logging to a custom path.
|
||||
*
|
||||
* @see https://www.elastic.co/guide/en/elasticsearch/client/php-api/2.0/_configuration.html#enabling_logger
|
||||
*/
|
||||
|
||||
'logging' => false,
|
||||
|
||||
// If you have an existing instance of Monolog you can use it here.
|
||||
//'logObject' => \Log::getMonolog(),
|
||||
|
||||
'logPath' => storage_path('logs/elasticsearch.log'),
|
||||
|
||||
'logLevel' => Monolog\Logger::INFO,
|
||||
|
||||
/**
|
||||
* Retries
|
||||
*
|
||||
* By default, the client will retry n times, where n = number of nodes in
|
||||
* your cluster. If you would like to disable retries, or change the number,
|
||||
* you can do so here.
|
||||
*
|
||||
* @see https://www.elastic.co/guide/en/elasticsearch/client/php-api/2.0/_configuration.html#_set_retries
|
||||
*/
|
||||
|
||||
'retries' => null,
|
||||
|
||||
/**
|
||||
* The remainder of the configuration options can almost always be left
|
||||
* as-is unless you have specific reasons to change them. Refer to the
|
||||
* appropriate sections in the Elasticsearch documentation for what each option
|
||||
* does and what values it expects.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sniff On Start
|
||||
*
|
||||
* @see https://www.elastic.co/guide/en/elasticsearch/client/php-api/2.0/_configuration.html
|
||||
*/
|
||||
|
||||
'sniffOnStart' => false,
|
||||
|
||||
/**
|
||||
* HTTP Handler
|
||||
*
|
||||
* @see https://www.elastic.co/guide/en/elasticsearch/client/php-api/2.0/_configuration.html#_configure_the_http_handler
|
||||
* @see http://ringphp.readthedocs.org/en/latest/client_handlers.html
|
||||
*/
|
||||
|
||||
'httpHandler' => null,
|
||||
|
||||
/**
|
||||
* Connection Pool
|
||||
*
|
||||
* @see https://www.elastic.co/guide/en/elasticsearch/client/php-api/2.0/_configuration.html#_setting_the_connection_pool
|
||||
* @see https://www.elastic.co/guide/en/elasticsearch/client/php-api/2.0/_connection_pool.html
|
||||
*/
|
||||
|
||||
'connectionPool' => null,
|
||||
|
||||
/**
|
||||
* Connection Selector
|
||||
*
|
||||
* @see https://www.elastic.co/guide/en/elasticsearch/client/php-api/2.0/_configuration.html#_setting_the_connection_selector
|
||||
* @see https://www.elastic.co/guide/en/elasticsearch/client/php-api/2.0/_selectors.html
|
||||
*/
|
||||
|
||||
'connectionSelector' => null,
|
||||
|
||||
/**
|
||||
* Serializer
|
||||
*
|
||||
* @see https://www.elastic.co/guide/en/elasticsearch/client/php-api/2.0/_configuration.html#_setting_the_serializer
|
||||
* @see https://www.elastic.co/guide/en/elasticsearch/client/php-api/2.0/_serializers.html
|
||||
*/
|
||||
|
||||
'serializer' => null,
|
||||
|
||||
/**
|
||||
* Connection Factory
|
||||
*
|
||||
* @see https://www.elastic.co/guide/en/elasticsearch/client/php-api/2.0/_configuration.html#_setting_a_custom_connectionfactory
|
||||
*/
|
||||
|
||||
'connectionFactory' => null,
|
||||
|
||||
/**
|
||||
* Endpoint
|
||||
*
|
||||
* @see https://www.elastic.co/guide/en/elasticsearch/client/php-api/2.0/_configuration.html#_set_the_endpoint_closure
|
||||
*/
|
||||
|
||||
'endpoint' => null,
|
||||
|
||||
]
|
||||
]
|
||||
|
||||
];
|
|
@ -56,7 +56,7 @@ return [
|
|||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cache Duration
|
||||
| Cache duration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Duration in minutes for track files to be stored in cache.
|
||||
|
@ -65,4 +65,28 @@ return [
|
|||
|
||||
'track_file_cache_duration' => 1440,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Elasticsearch index name
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The name of the Elasticsearch index to store Pony.fm's search data in.
|
||||
|
|
||||
*/
|
||||
|
||||
'elasticsearch_index' => 'ponyfm',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Indexing queue name
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The name of the queue to process re-indexing jobs on. This is separated
|
||||
| from the default queue to avoid having a site-wide re-index clog uploads
|
||||
| and downloads.
|
||||
|
|
||||
*/
|
||||
|
||||
'indexing_queue' => 'indexing',
|
||||
|
||||
];
|
||||
|
|
|
@ -35,13 +35,6 @@ return [
|
|||
'driver' => 'sync',
|
||||
],
|
||||
|
||||
'database' => [
|
||||
'driver' => 'database',
|
||||
'table' => 'jobs',
|
||||
'queue' => 'default',
|
||||
'expire' => 60,
|
||||
],
|
||||
|
||||
'beanstalkd' => [
|
||||
'driver' => 'beanstalkd',
|
||||
'host' => 'localhost',
|
||||
|
@ -49,30 +42,6 @@ return [
|
|||
'ttr' => 60,
|
||||
],
|
||||
|
||||
'sqs' => [
|
||||
'driver' => 'sqs',
|
||||
'key' => 'your-public-key',
|
||||
'secret' => 'your-secret-key',
|
||||
'queue' => 'your-queue-url',
|
||||
'region' => 'us-east-1',
|
||||
],
|
||||
|
||||
'iron' => [
|
||||
'driver' => 'iron',
|
||||
'host' => 'mq-aws-us-east-1.iron.io',
|
||||
'token' => 'your-token',
|
||||
'project' => 'your-project-id',
|
||||
'queue' => 'your-queue-name',
|
||||
'encrypt' => true,
|
||||
],
|
||||
|
||||
'redis' => [
|
||||
'driver' => 'redis',
|
||||
'connection' => 'default',
|
||||
'queue' => 'default',
|
||||
'expire' => 60,
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|
|
115
database/migrations/2016_01_14_021607_setup_elasticsearch.php
Normal file
115
database/migrations/2016_01_14_021607_setup_elasticsearch.php
Normal file
|
@ -0,0 +1,115 @@
|
|||
<?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\Migrations\Migration;
|
||||
|
||||
class SetupElasticsearch extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
$elasticsearch = Elasticsearch::connection();
|
||||
|
||||
$elasticsearch->indices()->create([
|
||||
'index' => 'ponyfm',
|
||||
'body' => [
|
||||
'mappings' => [
|
||||
'track' => [
|
||||
'_source' => ['enabled' => true],
|
||||
'dynamic' => 'strict',
|
||||
'properties' => [
|
||||
'title' => ['type' => 'string', 'analyzer' => 'english'],
|
||||
'artist' => ['type' => 'string'],
|
||||
|
||||
'published_at' => ['type' => 'date'],
|
||||
'genre' => ['type' => 'string', 'analyzer' => 'english'],
|
||||
'track_type' => ['type' => 'string', 'index' => 'not_analyzed'],
|
||||
|
||||
// This field is intended to be used as an array.
|
||||
// Note that all Elasticsearch fields can technically be used as arrays.
|
||||
// See: https://www.elastic.co/guide/en/elasticsearch/reference/current/array.html
|
||||
'show_songs' => ['type' => 'string'],
|
||||
]
|
||||
],
|
||||
|
||||
'album' => [
|
||||
'_source' => ['enabled' => true],
|
||||
'dynamic' => 'strict',
|
||||
'properties' => [
|
||||
'title' => ['type' => 'string', 'analyzer' => 'english'],
|
||||
'artist' => ['type' => 'string'],
|
||||
|
||||
// This field is intended to be used as an array.
|
||||
// Note that all Elasticsearch fields can technically be used as arrays.
|
||||
// See: https://www.elastic.co/guide/en/elasticsearch/reference/current/array.html
|
||||
'tracks' => ['type' => 'string', 'analyzer' => 'english']
|
||||
]
|
||||
],
|
||||
|
||||
'playlist' => [
|
||||
'_source' => ['enabled' => true],
|
||||
'dynamic' => 'strict',
|
||||
'properties' => [
|
||||
'title' => ['type' => 'string', 'analyzer' => 'english'],
|
||||
'curator' => ['type' => 'string'],
|
||||
|
||||
// This field is intended to be used as an array.
|
||||
// Note that all Elasticsearch fields can technically be used as arrays.
|
||||
// See: https://www.elastic.co/guide/en/elasticsearch/reference/current/array.html
|
||||
'tracks' => ['type' => 'string', 'analyzer' => 'english']
|
||||
]
|
||||
],
|
||||
|
||||
'user' => [
|
||||
'_source' => ['enabled' => true],
|
||||
'dynamic' => 'strict',
|
||||
'properties' => [
|
||||
'username' => ['type' => 'string', 'index' => 'not_analyzed'],
|
||||
'display_name' => ['type' => 'string'],
|
||||
|
||||
// This field is intended to be used as an array.
|
||||
// Note that all Elasticsearch fields can technically be used as arrays.
|
||||
// See: https://www.elastic.co/guide/en/elasticsearch/reference/current/array.html
|
||||
'tracks' => ['type' => 'string', 'analyzer' => 'english']
|
||||
]
|
||||
],
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
Artisan::call('rebuild:search');
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
$elasticsearch = Elasticsearch::connection();
|
||||
|
||||
$elasticsearch->indices()->delete(['index' => 'ponyfm']);
|
||||
}
|
||||
}
|
|
@ -25,7 +25,7 @@
|
|||
<pfm-image-upload set-image="setCover" image="album.cover" />
|
||||
</div>
|
||||
<div class="form-row track-selector">
|
||||
<a pfm-popup="track-selector,right" href="#" class="btn btn-small pull-right btn-info">Add Tracks</a>
|
||||
<a pfm-popup="track-selector,right" pfm-popup-close-on-click href="#" class="btn btn-small pull-right btn-info">Add Tracks</a>
|
||||
<label class="strong">Album Tracks</label>
|
||||
<div id="track-selector" class="pfm-popup">
|
||||
<ul>
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="form-row album span6" ng-class="{'has-error': errors.album_id != null}">
|
||||
<a pfm-popup="album-selector" href="#" class="btn btn-small">
|
||||
<a pfm-popup="album-selector" pfm-popup-close-on-click href="#" class="btn btn-small">
|
||||
Album:
|
||||
<strong ng-show="selectedAlbum">{{selectedAlbum.title}}</strong>
|
||||
<strong ng-hide="selectedAlbum">None</strong>
|
||||
|
@ -68,7 +68,7 @@
|
|||
<div class="error">{{errors.album_id}}</div>
|
||||
</div>
|
||||
<div class="form-row show-songs span6" ng-show="edit.track_type_id == 2" ng-class="{'has-error': errors.show_song_ids != null}">
|
||||
<a pfm-popup="song-selector" href="#" class="btn btn-small">Show Songs: <strong>{{selectedSongsTitle}}</strong></a>
|
||||
<a pfm-popup="song-selector" pfm-popup-close-on-click href="#" class="btn btn-small">Show Songs: <strong>{{selectedSongsTitle}}</strong></a>
|
||||
<div id="song-selector" class="pfm-popup">
|
||||
<ul>
|
||||
<li ng-repeat="song in taxonomies.showSongs" ng-class="{selected: selectedSongs[song.id]}">
|
||||
|
|
|
@ -1,21 +1,3 @@
|
|||
<div class="stretch-to-bottom">
|
||||
<ul class="artist-listing">
|
||||
<li class="artist" ng-class="{'x-archived': artist.is_archived}" ng-repeat="artist in artists" bindonce>
|
||||
<a href="{{artist.url}}">
|
||||
<img class="image" pfm-src-loader="artist.avatars.small" pfm-src-size="small" />
|
||||
<span class="info">
|
||||
<span class="title" bo-text="artist.name"></span>
|
||||
<span ng-hide="artist.is_archived" class="published">
|
||||
joined <span bo-text="artist.created_at.date | momentFromNow"></span>
|
||||
</span>
|
||||
<span ng-show="artist.is_archived" class="published">
|
||||
archived artist
|
||||
</span>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
<li ng-show="!artists.length" class="empty">
|
||||
No artists found...
|
||||
</li>
|
||||
</ul>
|
||||
<pfm-users-list users="artists"></pfm-users-list>
|
||||
</div>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<input type="file" onchange="angular.element(this).scope().setImageFile(this)" />
|
||||
</p>
|
||||
<div class="btn-group">
|
||||
<a href="#" pfm-popup="image-selector" class="btn btn-small"><i class="icon-picture"></i> Gallery</a>
|
||||
<a href="#" pfm-popup="image-selector" pfm-popup-close-on-click class="btn btn-small"><i class="icon-picture"></i> Gallery</a>
|
||||
<a href="#" pfm-eat-click ng-click="uploadImage()" class="btn btn-info btn-small"><i class="icon-upload"></i> Upload</a>
|
||||
<a href="#" pfm-eat-click ng-click="clearImage()" class="btn btn-danger btn-small" ng-show="isImageLoaded"><i class="icon-remove"></i></a>
|
||||
</div>
|
||||
|
|
34
public/templates/directives/search.html
Normal file
34
public/templates/directives/search.html
Normal file
|
@ -0,0 +1,34 @@
|
|||
<div class="search" ng-blur="searchInProgress = false">
|
||||
<input
|
||||
class="search-input"
|
||||
type="text"
|
||||
placeholder="Search…"
|
||||
ng-model="searchQuery"
|
||||
pfm-popup="search-results"
|
||||
/>
|
||||
|
||||
<section class="search-results pfm-popup" id="search-results">
|
||||
<div ng-hide="searchInProgress">
|
||||
<p class="empty-box">Type something to begin searching!</p>
|
||||
</div>
|
||||
|
||||
<div ng-show="searchInProgress">
|
||||
<div class="-column1">
|
||||
<h3 class="-section-header">Matching tracks</h3>
|
||||
<pfm-tracks-list tracks="tracks"></pfm-tracks-list>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="-column2">
|
||||
<h3 class="-section-header">Matching users</h3>
|
||||
<pfm-users-list users="users" class="-condensed"></pfm-users-list>
|
||||
|
||||
<h3 class="-section-header">Matching albums</h3>
|
||||
<pfm-albums-list albums="albums"></pfm-albums-list>
|
||||
|
||||
<h3 class="-section-header">Matching playlists</h3>
|
||||
<pfm-playlists-list playlists="playlists"></pfm-playlists-list>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
19
public/templates/directives/users-list.html
Normal file
19
public/templates/directives/users-list.html
Normal file
|
@ -0,0 +1,19 @@
|
|||
<ul class="users-listing">
|
||||
<li class="artist" ng-class="{'x-archived': user.is_archived}" ng-repeat="user in users track by user.id" bindonce>
|
||||
<a bo-href="user.url">
|
||||
<img class="image" pfm-src-loader="user.avatars.small" pfm-src-size="small" />
|
||||
<span class="info">
|
||||
<span class="title" bo-text="user.name"></span>
|
||||
<span ng-hide="user.is_archived" class="published">
|
||||
joined <span bo-text="user.created_at.date | momentFromNow"></span>
|
||||
</span>
|
||||
<span ng-show="user.is_archived" class="published">
|
||||
archived artist
|
||||
</span>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
<li ng-show="!users.length" class="empty">
|
||||
No users found…
|
||||
</li>
|
||||
</ul>
|
|
@ -27,20 +27,41 @@ angular.module('ponyfm').directive 'pfmPopup', () ->
|
|||
$element = $ element
|
||||
$positionParent = null
|
||||
open = false
|
||||
closeOnClick = attrs.pfmPopupCloseOnClick?
|
||||
|
||||
|
||||
documentClickHandler = () ->
|
||||
return if !open
|
||||
close = () ->
|
||||
$popup.removeClass 'open'
|
||||
open = false
|
||||
|
||||
|
||||
documentClickHandler = (event) ->
|
||||
if !open
|
||||
return
|
||||
|
||||
if (closeOnClick)
|
||||
close()
|
||||
return true
|
||||
|
||||
# Based on: https://stackoverflow.com/a/4660738/3225811
|
||||
else if event.target.id == elementId or $(event.target).parents("##{elementId}").size()
|
||||
return true
|
||||
|
||||
else
|
||||
close()
|
||||
return true
|
||||
|
||||
|
||||
calculatePosition = ->
|
||||
$popup.parents().each () ->
|
||||
$this = $ this
|
||||
$positionParent = $this if $positionParent == null && ($this.css('position') == 'relative' || $this.is 'body')
|
||||
|
||||
if $positionParent == null && ($this.css('position') == 'relative' || $this.is 'body')
|
||||
$positionParent = $this
|
||||
return false
|
||||
|
||||
position = $element.offset()
|
||||
parentPosition = $positionParent.offset()
|
||||
parentPosition = $positionParent.offset() + $positionParent.height()
|
||||
|
||||
windowWidth = $(window).width() - 15
|
||||
left = position.left
|
||||
|
@ -63,6 +84,7 @@ angular.module('ponyfm').directive 'pfmPopup', () ->
|
|||
top: top - parentPosition.top,
|
||||
height: height - 15}
|
||||
|
||||
|
||||
windowResizeHandler = () ->
|
||||
return if !open
|
||||
$popup.css 'height', 'auto'
|
||||
|
@ -70,7 +92,7 @@ angular.module('ponyfm').directive 'pfmPopup', () ->
|
|||
$popup.css
|
||||
left: position.left
|
||||
top: position.top
|
||||
height: position.height
|
||||
maxHeight: position.height
|
||||
|
||||
$(document.body).bind 'click', documentClickHandler
|
||||
$(window).bind 'resize', windowResizeHandler
|
||||
|
@ -79,9 +101,8 @@ angular.module('ponyfm').directive 'pfmPopup', () ->
|
|||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
|
||||
if open
|
||||
open = false
|
||||
$popup.removeClass 'open'
|
||||
if open and not $element.is(':focus')
|
||||
close
|
||||
return
|
||||
|
||||
$popup.addClass 'open'
|
||||
|
@ -97,6 +118,11 @@ angular.module('ponyfm').directive 'pfmPopup', () ->
|
|||
open = true
|
||||
), 0
|
||||
|
||||
|
||||
scope.$on '$stateChangeStart', () ->
|
||||
close()
|
||||
|
||||
|
||||
scope.$on '$destroy', () ->
|
||||
$(document.body).unbind 'click', documentClickHandler
|
||||
$(window).unbind 'click', windowResizeHandler
|
||||
|
|
66
resources/assets/scripts/app/directives/search.coffee
Normal file
66
resources/assets/scripts/app/directives/search.coffee
Normal file
|
@ -0,0 +1,66 @@
|
|||
# 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/>.
|
||||
|
||||
angular.module('ponyfm').directive 'pfmSearch', () ->
|
||||
restrict: 'E'
|
||||
templateUrl: '/templates/directives/search.html'
|
||||
scope:
|
||||
resource: '=resource',
|
||||
type: '@type'
|
||||
|
||||
controller: [
|
||||
'$scope', 'search'
|
||||
($scope, search) ->
|
||||
$scope.searchQuery = ''
|
||||
$scope.searchInProgress = false
|
||||
|
||||
$scope.tracks = []
|
||||
$scope.albums = []
|
||||
$scope.playlists = []
|
||||
$scope.users = []
|
||||
|
||||
clearResults = ()->
|
||||
$scope.tracks.length = 0
|
||||
$scope.albums.length = 0
|
||||
$scope.playlists.length = 0
|
||||
$scope.users.length = 0
|
||||
|
||||
|
||||
$scope.$watch 'searchQuery', _.debounce((searchQuery)->
|
||||
$scope.$apply ()->
|
||||
if searchQuery.length <3
|
||||
clearResults()
|
||||
$scope.searchInProgress = false
|
||||
return
|
||||
|
||||
$scope.searchInProgress = true
|
||||
|
||||
search.searchAllContent(searchQuery)
|
||||
.then (results)->
|
||||
clearResults()
|
||||
for track in results.tracks
|
||||
$scope.tracks.push(track)
|
||||
|
||||
for album in results.albums
|
||||
$scope.albums.push(album)
|
||||
|
||||
for playlist in results.playlists
|
||||
$scope.playlists.push(playlist)
|
||||
|
||||
for user in results.users
|
||||
$scope.users.push(user)
|
||||
, 300)
|
||||
]
|
29
resources/assets/scripts/app/directives/users-list.coffee
Normal file
29
resources/assets/scripts/app/directives/users-list.coffee
Normal file
|
@ -0,0 +1,29 @@
|
|||
# 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/>.
|
||||
|
||||
angular.module('ponyfm').directive 'pfmUsersList', () ->
|
||||
restrict: 'E'
|
||||
replace: true
|
||||
templateUrl: '/templates/directives/users-list.html'
|
||||
scope:
|
||||
users: '=users',
|
||||
class: '@class'
|
||||
|
||||
controller: [
|
||||
'$scope', 'auth'
|
||||
($scope, auth) ->
|
||||
$scope.auth = auth.data
|
||||
]
|
35
resources/assets/scripts/app/services/search.coffee
Normal file
35
resources/assets/scripts/app/services/search.coffee
Normal file
|
@ -0,0 +1,35 @@
|
|||
# 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/>.
|
||||
|
||||
angular.module('ponyfm').factory('search', [
|
||||
'$http'
|
||||
($http) ->
|
||||
|
||||
self =
|
||||
searchAllContent: (query) ->
|
||||
searchDef = new $.Deferred()
|
||||
|
||||
$http.get('/api/web/search?query=' + encodeURIComponent(query))
|
||||
.success (results)->
|
||||
searchDef.resolve(results.results)
|
||||
|
||||
.error (response)->
|
||||
searchDef.reject(response)
|
||||
|
||||
searchDef.promise()
|
||||
|
||||
self
|
||||
])
|
1
resources/assets/styles/app.less
vendored
1
resources/assets/styles/app.less
vendored
|
@ -32,3 +32,4 @@
|
|||
@import 'content';
|
||||
@import 'dashboard';
|
||||
@import 'uploader';
|
||||
@import 'search';
|
||||
|
|
53
resources/assets/styles/content.less
vendored
53
resources/assets/styles/content.less
vendored
|
@ -22,7 +22,7 @@
|
|||
|
||||
@media (max-width: 1300px) and (min-width: 720px) {
|
||||
html {
|
||||
.albums-listing, .playlists-listing, .artist-listing {
|
||||
.albums-listing, .playlists-listing, .users-listing {
|
||||
&.two-columns li {
|
||||
width: auto;
|
||||
float: none;
|
||||
|
@ -37,7 +37,7 @@
|
|||
|
||||
@media (max-width: 720px) {
|
||||
html {
|
||||
.albums-listing, .playlists-listing, .artist-listing {
|
||||
.albums-listing, .playlists-listing, .users-listing {
|
||||
&.two-columns li {
|
||||
width: auto;
|
||||
float: none;
|
||||
|
@ -51,7 +51,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
.albums-listing, .playlists-listing, .artist-listing {
|
||||
.albums-listing, .playlists-listing, .users-listing {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
list-style: none;
|
||||
|
@ -345,6 +345,23 @@ html .single-player .play-button {
|
|||
html {
|
||||
li {
|
||||
&.empty {
|
||||
.empty-box;
|
||||
}
|
||||
|
||||
.cache-loading {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
text-align: center;
|
||||
line-height: 100%;
|
||||
font-size: 93%;
|
||||
padding-left: 3px;
|
||||
padding-right: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.empty-box {
|
||||
.border-radius(0px);
|
||||
background: lighten(@pfm-purple, 30%);
|
||||
border: 1px solid lighten(@pfm-purple, 10%);
|
||||
|
@ -359,19 +376,6 @@ html {
|
|||
&:hover {
|
||||
background-color: lighten(@pfm-purple, 30%);
|
||||
}
|
||||
}
|
||||
|
||||
.cache-loading {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
text-align: center;
|
||||
line-height: 100%;
|
||||
font-size: 93%;
|
||||
padding-left: 3px;
|
||||
padding-right: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tracks-listing {
|
||||
|
@ -487,3 +491,20 @@ html {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.users-listing {
|
||||
&.-condensed {
|
||||
.image {
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
.info {
|
||||
margin-left: 40px;
|
||||
}
|
||||
|
||||
.published {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
74
resources/assets/styles/search.less
vendored
Normal file
74
resources/assets/styles/search.less
vendored
Normal file
|
@ -0,0 +1,74 @@
|
|||
/**
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
@import 'base/bootstrap/bootstrap';
|
||||
@import 'mixins';
|
||||
@import 'variables';
|
||||
|
||||
.search {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
input.search-input {
|
||||
font-size: 13px;
|
||||
padding: 15px 10px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.search-results {
|
||||
width: 600px;
|
||||
padding: 10px;
|
||||
|
||||
background: #fff;
|
||||
|
||||
.-column1, .-column2 {
|
||||
width: 48%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.-column1 {
|
||||
padding-right: 2%;
|
||||
}
|
||||
|
||||
.-column2 {
|
||||
padding-left: 2%;
|
||||
}
|
||||
|
||||
ol li {
|
||||
list-style: disc;
|
||||
}
|
||||
|
||||
li a {
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
color: @pfm-light-grey;
|
||||
}
|
||||
|
||||
.-section-header {
|
||||
background: transparent;
|
||||
color: @pfm-purple;
|
||||
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.albums-listing, .playlists-listing, .users-listing {
|
||||
li {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,6 +8,8 @@ DB_DATABASE=homestead
|
|||
DB_USERNAME=homestead
|
||||
DB_PASSWORD=secret
|
||||
|
||||
ELASTICSEARCH_HOSTS=localhost
|
||||
|
||||
SESSION_HTTPS_ONLY=false
|
||||
QUEUE_DRIVER=sync
|
||||
|
||||
|
|
|
@ -66,6 +66,9 @@
|
|||
|
||||
<div class="site-body">
|
||||
<ul class="sidebar" ng-controller="sidebar">
|
||||
@can('access-search')
|
||||
<li><pfm-search></pfm-search></li>
|
||||
@endcan
|
||||
<li ng-class="{selected: stateIncludes('content.tracks') || stateIncludes('content.track')}"><a href="/tracks">Tracks</a></li>
|
||||
<li ng-class="{selected: stateIncludes('content.albums') || stateIncludes('content.album')}"><a href="/albums">Albums</a></li>
|
||||
<li ng-class="{selected: stateIncludes('content.playlists') || stateIncludes('content.playlist')}"><a href="/playlists">Playlists</a></li>
|
||||
|
|
|
@ -7,6 +7,7 @@ sudo cp /vagrant/vagrant/php-overrides.ini /etc/php/7.0/fpm/99-overrides.ini
|
|||
|
||||
sudo cp /vagrant/vagrant/pony.fm.redis.config /etc/redis/redis.conf
|
||||
|
||||
sudo service elasticsearch restart
|
||||
sudo service nginx restart
|
||||
sudo service php7.0-fpm restart
|
||||
|
||||
|
|
|
@ -1,13 +1,28 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
|
||||
if type java &>/dev/null; then
|
||||
echo "Java is installed!"
|
||||
else
|
||||
sudo add-apt-repository -y ppa:webupd8team/java
|
||||
echo /usr/bin/debconf shared/accepted-oracle-license-v1-1 select true | sudo debconf-set-selections
|
||||
echo /usr/bin/debconf shared/accepted-oracle-license-v1-1 seen true | sudo debconf-set-selections
|
||||
fi
|
||||
|
||||
|
||||
if type /usr/share/elasticsearch/bin/elasticsearch &>/dev/null; then
|
||||
echo "ElasticSearch is installed!"
|
||||
else
|
||||
wget -qO - https://packages.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add -
|
||||
echo "deb http://packages.elastic.co/elasticsearch/2.x/debian stable main" | sudo tee -a /etc/apt/sources.list.d/elasticsearch-2.x.list
|
||||
fi
|
||||
|
||||
|
||||
echo "Running apt-get update..."
|
||||
sudo apt-get -qq update
|
||||
|
||||
echo "Installing tagging tools..."
|
||||
sudo apt-get -qq install -y AtomicParsley flac vorbis-tools imagemagick
|
||||
|
||||
echo "Installing ffmpeg dependencies.."
|
||||
sudo apt-get -qq install -y pkg-config yasm libfaac-dev libmp3lame-dev libvorbis-dev libtheora-dev
|
||||
echo "Installing tagging tools & other dependencies..."
|
||||
sudo apt-get -qq install -y AtomicParsley flac vorbis-tools imagemagick oracle-java8-installer elasticsearch pkg-config yasm libfaac-dev libmp3lame-dev libvorbis-dev libtheora-dev
|
||||
|
||||
|
||||
if type ffmpeg &>/dev/null; then
|
||||
|
|
Loading…
Reference in a new issue