debounce search OK
This commit is contained in:
parent
0f1ea1f5d0
commit
431cbf0c42
@ -13,6 +13,7 @@ declare(strict_types=1);
|
||||
return [
|
||||
'routes' => [
|
||||
['name' => 'page#index', 'url' => '/', 'verb' => 'GET'],
|
||||
['name' => 'top#index', 'url' => '/top/{count}', 'verb' => 'GET']
|
||||
['name' => 'top#index', 'url' => '/top/{count}', 'verb' => 'GET'],
|
||||
['name' => 'search#index', 'url' => '/search/{value}', 'verb' => 'GET']
|
||||
]
|
||||
];
|
||||
|
55
lib/Controller/SearchController.php
Normal file
55
lib/Controller/SearchController.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OCA\RePod\Controller;
|
||||
|
||||
use Exception;
|
||||
use OCA\RePod\AppInfo\Application;
|
||||
use OCP\AppFramework\Controller;
|
||||
use OCP\AppFramework\Http\JSONResponse;
|
||||
use OCP\Http\Client\IClientService;
|
||||
use OCP\IRequest;
|
||||
|
||||
class SearchController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
IRequest $request,
|
||||
private IClientService $clientService
|
||||
) {
|
||||
parent::__construct(Application::APP_ID, $request);
|
||||
}
|
||||
|
||||
public function index(string $value): JSONResponse {
|
||||
$podcasts = [];
|
||||
|
||||
try {
|
||||
$fyydClient = $this->clientService->newClient();
|
||||
$fyydReponse = $fyydClient->get("https://api.fyyd.de/0.2/search/podcast", [
|
||||
'query' => [
|
||||
'title' => $value,
|
||||
'term' => $value
|
||||
]
|
||||
]);
|
||||
$fyydJson = (array) json_decode((string) $fyydReponse->getBody(), true, flags: JSON_THROW_ON_ERROR);
|
||||
|
||||
if (array_key_exists('data', $fyydJson) && is_array($fyydJson['data'])) {
|
||||
/** @var string[] $fyydFeed */
|
||||
foreach ($fyydJson['data'] as $fyydFeed) {
|
||||
$podcasts[] = [
|
||||
'id' => $fyydFeed['id'],
|
||||
'title' => $fyydFeed['title'],
|
||||
'description' => $fyydFeed['description'],
|
||||
'image' => $fyydFeed['imgURL'],
|
||||
'url' => $fyydFeed['xmlURL'],
|
||||
'lang' => $fyydFeed['language'],
|
||||
'lastpub' => $fyydFeed['lastpub']
|
||||
];
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
|
||||
return new JSONResponse($podcasts);
|
||||
}
|
||||
}
|
@ -30,24 +30,29 @@ class TopController extends Controller
|
||||
* @NoCSRFRequired
|
||||
*/
|
||||
public function index(int $count = 10): JSONResponse {
|
||||
$userLang = 'en';
|
||||
$language = 'en';
|
||||
|
||||
try {
|
||||
$langClient = $this->clientService->newClient();
|
||||
$langResponse = $langClient->get("https://api.fyyd.de/0.2/feature/podcast/hot/languages");
|
||||
$langJson = (array) json_decode((string) $langResponse->getBody(), true, flags: JSON_THROW_ON_ERROR);
|
||||
if (array_key_exists('data', $langJson) && is_array($langJson['data'])) {
|
||||
$userLang = $this->l10n->getUserLanguage($this->userSession->getUser());
|
||||
$userLang = explode('_', $userLang);
|
||||
$userLang = count($userLang) > 1 ? $userLang[1] : $userLang[0];
|
||||
$userLang = in_array($userLang, $langJson['data']) ? $userLang : 'en';
|
||||
$language = $this->l10n->getUserLanguage($this->userSession->getUser());
|
||||
$language = explode('_', $language);
|
||||
$language = count($language) > 1 ? $language[1] : $language[0];
|
||||
$language = in_array($language, $langJson['data']) ? $language : 'en';
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
|
||||
try {
|
||||
$podcastClient = $this->clientService->newClient();
|
||||
$podcastReponse = $podcastClient->get("https://api.fyyd.de/0.2/feature/podcast/hot?count={$count}&language={$userLang}");
|
||||
$podcastReponse = $podcastClient->get("https://api.fyyd.de/0.2/feature/podcast/hot", [
|
||||
'query' => [
|
||||
'count' => $count,
|
||||
'language' => $language
|
||||
]
|
||||
]);
|
||||
$podcastJson = (array) json_decode((string) $podcastReponse->getBody(), true, flags: JSON_THROW_ON_ERROR);
|
||||
return new JSONResponse($podcastJson, $podcastReponse->getStatusCode());
|
||||
} catch (Exception $e) {
|
||||
|
52
src/components/Search.vue
Normal file
52
src/components/Search.vue
Normal file
@ -0,0 +1,52 @@
|
||||
<template>
|
||||
<ul>
|
||||
<NcListItem v-for="feed in feeds" :key="feed.id" />
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { NcListItem } from '@nextcloud/vue'
|
||||
import axios from '@nextcloud/axios'
|
||||
import { debounce } from '../utils/debounce.js'
|
||||
import { generateUrl } from '@nextcloud/router'
|
||||
import { showError } from '@nextcloud/dialogs'
|
||||
|
||||
export default {
|
||||
name: 'Search',
|
||||
components: {
|
||||
NcListItem,
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
feeds: [],
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value() {
|
||||
this.search()
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
search: debounce(async function value() {
|
||||
this.loading = true
|
||||
|
||||
try {
|
||||
const feeds = await axios.get(generateUrl('/apps/repod/search/{value}', { value: this.value }))
|
||||
this.feeds = feeds.data
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
showError(t('Could not fetch search results'))
|
||||
}
|
||||
|
||||
this.loading = false
|
||||
}, 200),
|
||||
},
|
||||
}
|
||||
</script>
|
@ -4,7 +4,7 @@
|
||||
<span>{{ t('Discover') }}</span>
|
||||
<NcSelect v-model="count"
|
||||
class="select"
|
||||
:components="{Deselect: {}}"
|
||||
:components="Deselect"
|
||||
:options="[...Array(10).keys()].map(x=>(x+1)*10)"
|
||||
@input="fetch" />
|
||||
</p>
|
||||
@ -39,6 +39,9 @@ export default {
|
||||
tops: [],
|
||||
loading: true,
|
||||
count: 10,
|
||||
Deselect: {
|
||||
render: null,
|
||||
},
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
|
20
src/utils/debounce.js
Normal file
20
src/utils/debounce.js
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Returns a function, that, as long as it continues to be invoked, will not
|
||||
* be triggered. The function will be called after it stops being called for
|
||||
* N milliseconds.
|
||||
* https://stackoverflow.com/a/53486112
|
||||
*
|
||||
* @param {Function} fn function to wrap
|
||||
* @param {number} delay timeout in ms
|
||||
*/
|
||||
export function debounce(fn, delay) {
|
||||
let timeoutID = null
|
||||
return function() {
|
||||
clearTimeout(timeoutID)
|
||||
const args = arguments
|
||||
const that = this
|
||||
timeoutID = setTimeout(function() {
|
||||
fn.apply(that, args)
|
||||
}, delay)
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@
|
||||
<Magnify :size="20" />
|
||||
</NcTextField>
|
||||
</p>
|
||||
<Search v-if="search" :value="search" />
|
||||
<TopList v-if="!search" />
|
||||
<AddRss v-if="!search" />
|
||||
</div>
|
||||
@ -14,6 +15,7 @@
|
||||
import AddRss from '../components/AddRss.vue'
|
||||
import Magnify from 'vue-material-design-icons/Magnify.vue'
|
||||
import { NcTextField } from '@nextcloud/vue'
|
||||
import Search from '../components/Search.vue'
|
||||
import TopList from '../components/TopList.vue'
|
||||
|
||||
export default {
|
||||
@ -22,6 +24,7 @@ export default {
|
||||
AddRss,
|
||||
Magnify,
|
||||
NcTextField,
|
||||
Search,
|
||||
TopList,
|
||||
},
|
||||
data() {
|
||||
|
Loading…
Reference in New Issue
Block a user