Merge pull request #316 from linuxserver/search-enhancements
Search enhancements
This commit is contained in:
commit
6dcbcb452e
13 changed files with 207 additions and 58 deletions
|
@ -12,6 +12,7 @@ use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use App\SupportedApps;
|
use App\SupportedApps;
|
||||||
use App\Jobs\ProcessApps;
|
use App\Jobs\ProcessApps;
|
||||||
|
use App\Search;
|
||||||
|
|
||||||
class ItemController extends Controller
|
class ItemController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -168,6 +169,8 @@ class ItemController extends Controller
|
||||||
|
|
||||||
$item = Item::create($request->all());
|
$item = Item::create($request->all());
|
||||||
|
|
||||||
|
Search::storeSearchProvider($request->input('class'), $item);
|
||||||
|
|
||||||
$item->parents()->sync($request->tags);
|
$item->parents()->sync($request->tags);
|
||||||
|
|
||||||
$route = route('dash', [], false);
|
$route = route('dash', [], false);
|
||||||
|
@ -241,6 +244,8 @@ class ItemController extends Controller
|
||||||
$item = Item::find($id);
|
$item = Item::find($id);
|
||||||
$item->update($request->all());
|
$item->update($request->all());
|
||||||
|
|
||||||
|
Search::storeSearchProvider($request->input('class'), $item);
|
||||||
|
|
||||||
$item->parents()->sync($request->tags);
|
$item->parents()->sync($request->tags);
|
||||||
|
|
||||||
$route = route('dash', [], false);
|
$route = route('dash', [], false);
|
||||||
|
|
28
app/Http/Controllers/SearchController.php
Normal file
28
app/Http/Controllers/SearchController.php
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Search;
|
||||||
|
|
||||||
|
class SearchController extends Controller
|
||||||
|
{
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$requestprovider = $request->input('provider');
|
||||||
|
$query = $request->input('q');
|
||||||
|
|
||||||
|
$provider = Search::providerDetails($requestprovider);
|
||||||
|
|
||||||
|
if($provider->type == 'standard') {
|
||||||
|
return redirect($provider->url.'?'.$provider->var.'='.urlencode($query));
|
||||||
|
} elseif($provider->type == 'external') {
|
||||||
|
$class = new $provider->class;
|
||||||
|
//print_r($provider);
|
||||||
|
return $class->getResults($query, $provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
//print_r($provider);
|
||||||
|
}
|
||||||
|
}
|
|
@ -118,4 +118,10 @@ class SettingsController extends Controller
|
||||||
]);
|
]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function search(Request $request)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -163,6 +163,12 @@ class Item extends Model
|
||||||
return (bool)($app instanceof \App\EnhancedApps);
|
return (bool)($app instanceof \App\EnhancedApps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function isSearchProvider($class)
|
||||||
|
{
|
||||||
|
$app = new $class;
|
||||||
|
return ((bool)($app instanceof \App\SearchInterface)) ? $app : false;
|
||||||
|
}
|
||||||
|
|
||||||
public function enabled()
|
public function enabled()
|
||||||
{
|
{
|
||||||
if($this->enhanced()) {
|
if($this->enhanced()) {
|
||||||
|
|
135
app/Search.php
Normal file
135
app/Search.php
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
<?php namespace App;
|
||||||
|
|
||||||
|
use GuzzleHttp\Exception\GuzzleException;
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
use App\Item;
|
||||||
|
use App\Setting;
|
||||||
|
use Form;
|
||||||
|
use Cache;
|
||||||
|
|
||||||
|
abstract class Search
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of all search providers
|
||||||
|
*
|
||||||
|
* @return Array
|
||||||
|
*/
|
||||||
|
public static function providers()
|
||||||
|
{
|
||||||
|
$providers = self::standardProviders();
|
||||||
|
$providers = $providers + self::appProviders();
|
||||||
|
return $providers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets details for a single provider
|
||||||
|
*
|
||||||
|
* @return Object
|
||||||
|
*/
|
||||||
|
public static function providerDetails($provider)
|
||||||
|
{
|
||||||
|
$providers = self::providers();
|
||||||
|
if(!isset($providers[$provider])) return false;
|
||||||
|
return (object)$providers[$provider] ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of the standard providers
|
||||||
|
*
|
||||||
|
* @return Array
|
||||||
|
*/
|
||||||
|
public static function standardProviders()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'google' => [
|
||||||
|
'url' => 'https://www.google.com/search',
|
||||||
|
'var' => 'q',
|
||||||
|
'method' => 'get',
|
||||||
|
'type' => 'standard',
|
||||||
|
],
|
||||||
|
'ddg' => [
|
||||||
|
'url' => 'https://duckduckgo.com/',
|
||||||
|
'var' => 'q',
|
||||||
|
'method' => 'get',
|
||||||
|
'type' => 'standard',
|
||||||
|
],
|
||||||
|
'bing' => [
|
||||||
|
'url' => 'https://www.bing.com/search',
|
||||||
|
'var' => 'q',
|
||||||
|
'method' => 'get',
|
||||||
|
'type' => 'standard',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loops through users apps to see if app is a search provider, might be worth
|
||||||
|
* looking into caching this at some point
|
||||||
|
*
|
||||||
|
* @return Array
|
||||||
|
*/
|
||||||
|
public static function appProviders()
|
||||||
|
{
|
||||||
|
$providers = [];
|
||||||
|
$userapps = Item::all();
|
||||||
|
foreach($userapps as $app) {
|
||||||
|
if(empty($app->class)) continue;
|
||||||
|
if(($provider = Item::isSearchProvider($app->class)) !== false) {
|
||||||
|
$name = Item::nameFromClass($app->class);
|
||||||
|
$providers[strtolower($name)] = [
|
||||||
|
'type' => $provider->type,
|
||||||
|
'class' => $app->class,
|
||||||
|
'url' => $app->url,
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $providers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Outputs the search form
|
||||||
|
*
|
||||||
|
* @return html
|
||||||
|
*/
|
||||||
|
public static function form()
|
||||||
|
{
|
||||||
|
$output = '';
|
||||||
|
$homepage_search = Setting::fetch('homepage_search');
|
||||||
|
$search_provider = Setting::where('key', '=', 'search_provider')->first();
|
||||||
|
$user_search_provider = Setting::fetch('search_provider');
|
||||||
|
//die(print_r($search_provider));
|
||||||
|
|
||||||
|
//die(var_dump($user_search_provider));
|
||||||
|
// return early if search isn't applicable
|
||||||
|
if((bool)$homepage_search !== true) return $output;
|
||||||
|
$user_search_provider = $user_search_provider ?? 'none';
|
||||||
|
|
||||||
|
if((bool)$homepage_search && (bool)$search_provider) {
|
||||||
|
|
||||||
|
if((bool)$user_search_provider) {
|
||||||
|
$name = 'app.options.'.$user_search_provider;
|
||||||
|
$provider = self::providerDetails($user_search_provider);
|
||||||
|
|
||||||
|
$output .= '<div class="searchform">';
|
||||||
|
$output .= Form::open(['url' => 'search', 'method' => 'get']);
|
||||||
|
$output .= '<div id="search-container" class="input-container">';
|
||||||
|
$output .= '<select name="provider">';
|
||||||
|
foreach(self::providers() as $key => $searchprovider) {
|
||||||
|
$selected = ($key === $user_search_provider) ? ' selected="selected"' : '';
|
||||||
|
$output .= '<option value="'.$key.'"'.$selected.'>'.__('app.options.'.$key).'</option>';
|
||||||
|
}
|
||||||
|
$output .= '</select>';
|
||||||
|
$output .= Form::text('q', null, ['class' => 'homesearch', 'autofocus' => 'autofocus', 'placeholder' => __('app.settings.search').'...']);
|
||||||
|
$output .= '<button type="submit">'.ucwords(__('app.settings.search')).'</button>';
|
||||||
|
$output .= '</div>';
|
||||||
|
$output .= Form::close();
|
||||||
|
$output .= '</div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
10
app/SearchInterface.php
Normal file
10
app/SearchInterface.php
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?php namespace App;
|
||||||
|
|
||||||
|
use GuzzleHttp\Exception\GuzzleException;
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
|
||||||
|
interface SearchInterface
|
||||||
|
{
|
||||||
|
public function getResults($query, $providerdetails);
|
||||||
|
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ use Illuminate\Support\Facades\Input;
|
||||||
use Form;
|
use Form;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use App\User;
|
use App\User;
|
||||||
|
use App\Search;
|
||||||
|
|
||||||
class Setting extends Model
|
class Setting extends Model
|
||||||
{
|
{
|
||||||
|
@ -216,59 +217,6 @@ class Setting extends Model
|
||||||
return array_key_exists($key, Setting::$cache);
|
return array_key_exists($key, Setting::$cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return html
|
|
||||||
*/
|
|
||||||
public static function search()
|
|
||||||
{
|
|
||||||
$output = '';
|
|
||||||
$homepage_search = self::fetch('homepage_search');
|
|
||||||
$search_provider = self::where('key', '=', 'search_provider')->first();
|
|
||||||
$user_search_provider = self::fetch('search_provider');
|
|
||||||
//die(print_r($search_provider));
|
|
||||||
|
|
||||||
//die(var_dump($user_search_provider));
|
|
||||||
// return early if search isn't applicable
|
|
||||||
if((bool)$homepage_search !== true) return $output;
|
|
||||||
if($user_search_provider === 'none') return $output;
|
|
||||||
if(empty($user_search_provider)) return $output;
|
|
||||||
if(is_null($user_search_provider)) return $output;
|
|
||||||
|
|
||||||
|
|
||||||
if((bool)$homepage_search && (bool)$search_provider) {
|
|
||||||
|
|
||||||
$options = (array)json_decode($search_provider->options);
|
|
||||||
$name = $options[$user_search_provider];
|
|
||||||
if((bool)$user_search_provider) {
|
|
||||||
switch($user_search_provider) {
|
|
||||||
case 'google':
|
|
||||||
$url = 'https://www.google.com/search';
|
|
||||||
$var = 'q';
|
|
||||||
break;
|
|
||||||
case 'ddg':
|
|
||||||
$url = 'https://duckduckgo.com/';
|
|
||||||
$var = 'q';
|
|
||||||
break;
|
|
||||||
case 'bing':
|
|
||||||
$url = 'https://www.bing.com/search';
|
|
||||||
$var = 'q';
|
|
||||||
break;
|
|
||||||
case 'startpage':
|
|
||||||
$url = 'https://www.startpage.com/';
|
|
||||||
$var = 'q';
|
|
||||||
}
|
|
||||||
$output .= '<div class="searchform">';
|
|
||||||
$output .= Form::open(['url' => $url, 'method' => 'get']);
|
|
||||||
$output .= '<div class="input-container">';
|
|
||||||
$output .= Form::text($var, null, ['class' => 'homesearch', 'autofocus' => 'autofocus', 'placeholder' => __($name).' '.__('app.settings.search').'...']);
|
|
||||||
$output .= '<button type="submit">'.ucwords(__('app.settings.search')).'</button>';
|
|
||||||
$output .= '</div>';
|
|
||||||
$output .= Form::close();
|
|
||||||
$output .= '</div>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $output;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The users that belong to the setting.
|
* The users that belong to the setting.
|
||||||
|
|
2
public/css/app.css
vendored
2
public/css/app.css
vendored
File diff suppressed because one or more lines are too long
4
public/mix-manifest.json
generated
4
public/mix-manifest.json
generated
|
@ -1,4 +1,4 @@
|
||||||
{
|
{
|
||||||
"/css/app.css": "/css/app.css?id=bfa06f05dc25570a993d",
|
"/css/app.css": "/css/app.css?id=c067b0b68e4516e903e1",
|
||||||
"/js/app.js": "/js/app.js?id=0db2e72b5cd42d83e306"
|
"/js/app.js": "/js/app.js?id=8dc4a6ea723d0df7469d"
|
||||||
}
|
}
|
||||||
|
|
|
@ -693,7 +693,7 @@ div.create {
|
||||||
border-bottom: 1px solid rgba(255,255,255,0.35);
|
border-bottom: 1px solid rgba(255,255,255,0.35);
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 500px;
|
max-width: 620px;
|
||||||
form {
|
form {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
@ -703,6 +703,8 @@ div.create {
|
||||||
box-shadow: 0px 0px 5px 0 rgba(0,0,0,0.4);
|
box-shadow: 0px 0px 5px 0 rgba(0,0,0,0.4);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
}
|
}
|
||||||
input {
|
input {
|
||||||
padding: 17px 15px;
|
padding: 17px 15px;
|
||||||
|
@ -726,6 +728,12 @@ div.create {
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
background: $app-red;
|
background: $app-red;
|
||||||
}
|
}
|
||||||
|
select {
|
||||||
|
padding: 0 10px;
|
||||||
|
background: #f5f5f5;
|
||||||
|
border: none;
|
||||||
|
border-right: 1px solid #ddd;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui-autocomplete {
|
.ui-autocomplete {
|
||||||
|
|
|
@ -42,6 +42,7 @@ return [
|
||||||
'options.startpage' => 'StartPage',
|
'options.startpage' => 'StartPage',
|
||||||
'options.yes' => 'Yes',
|
'options.yes' => 'Yes',
|
||||||
'options.no' => 'No',
|
'options.no' => 'No',
|
||||||
|
'options.nzbhydra' => 'NZBHydra',
|
||||||
|
|
||||||
'buttons.save' => 'Save',
|
'buttons.save' => 'Save',
|
||||||
'buttons.cancel' => 'Cancel',
|
'buttons.cancel' => 'Cancel',
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{!! App\Setting::search() !!}
|
{!! App\Search::form() !!}
|
||||||
|
|
|
@ -42,6 +42,8 @@ Route::post('appload', 'ItemController@appload')->name('appload');
|
||||||
Route::post('test_config', 'ItemController@testConfig')->name('test_config');
|
Route::post('test_config', 'ItemController@testConfig')->name('test_config');
|
||||||
Route::get('/get_stats/{id}', 'ItemController@getStats')->name('get_stats');
|
Route::get('/get_stats/{id}', 'ItemController@getStats')->name('get_stats');
|
||||||
|
|
||||||
|
Route::get('/search', 'SearchController@index')->name('search');
|
||||||
|
|
||||||
Route::get('view/{name_view}', function ($name_view) {
|
Route::get('view/{name_view}', function ($name_view) {
|
||||||
return view('SupportedApps::'.$name_view)->render();
|
return view('SupportedApps::'.$name_view)->render();
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue