debounce search OK
This commit is contained in:
parent
0f1ea1f5d0
commit
431cbf0c42
@ -13,6 +13,7 @@ declare(strict_types=1);
|
|||||||
return [
|
return [
|
||||||
'routes' => [
|
'routes' => [
|
||||||
['name' => 'page#index', 'url' => '/', 'verb' => 'GET'],
|
['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
|
* @NoCSRFRequired
|
||||||
*/
|
*/
|
||||||
public function index(int $count = 10): JSONResponse {
|
public function index(int $count = 10): JSONResponse {
|
||||||
$userLang = 'en';
|
$language = 'en';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$langClient = $this->clientService->newClient();
|
$langClient = $this->clientService->newClient();
|
||||||
$langResponse = $langClient->get("https://api.fyyd.de/0.2/feature/podcast/hot/languages");
|
$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);
|
$langJson = (array) json_decode((string) $langResponse->getBody(), true, flags: JSON_THROW_ON_ERROR);
|
||||||
if (array_key_exists('data', $langJson) && is_array($langJson['data'])) {
|
if (array_key_exists('data', $langJson) && is_array($langJson['data'])) {
|
||||||
$userLang = $this->l10n->getUserLanguage($this->userSession->getUser());
|
$language = $this->l10n->getUserLanguage($this->userSession->getUser());
|
||||||
$userLang = explode('_', $userLang);
|
$language = explode('_', $language);
|
||||||
$userLang = count($userLang) > 1 ? $userLang[1] : $userLang[0];
|
$language = count($language) > 1 ? $language[1] : $language[0];
|
||||||
$userLang = in_array($userLang, $langJson['data']) ? $userLang : 'en';
|
$language = in_array($language, $langJson['data']) ? $language : 'en';
|
||||||
}
|
}
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$podcastClient = $this->clientService->newClient();
|
$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);
|
$podcastJson = (array) json_decode((string) $podcastReponse->getBody(), true, flags: JSON_THROW_ON_ERROR);
|
||||||
return new JSONResponse($podcastJson, $podcastReponse->getStatusCode());
|
return new JSONResponse($podcastJson, $podcastReponse->getStatusCode());
|
||||||
} catch (Exception $e) {
|
} 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>
|
<span>{{ t('Discover') }}</span>
|
||||||
<NcSelect v-model="count"
|
<NcSelect v-model="count"
|
||||||
class="select"
|
class="select"
|
||||||
:components="{Deselect: {}}"
|
:components="Deselect"
|
||||||
:options="[...Array(10).keys()].map(x=>(x+1)*10)"
|
:options="[...Array(10).keys()].map(x=>(x+1)*10)"
|
||||||
@input="fetch" />
|
@input="fetch" />
|
||||||
</p>
|
</p>
|
||||||
@ -39,6 +39,9 @@ export default {
|
|||||||
tops: [],
|
tops: [],
|
||||||
loading: true,
|
loading: true,
|
||||||
count: 10,
|
count: 10,
|
||||||
|
Deselect: {
|
||||||
|
render: null,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async mounted() {
|
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" />
|
<Magnify :size="20" />
|
||||||
</NcTextField>
|
</NcTextField>
|
||||||
</p>
|
</p>
|
||||||
|
<Search v-if="search" :value="search" />
|
||||||
<TopList v-if="!search" />
|
<TopList v-if="!search" />
|
||||||
<AddRss v-if="!search" />
|
<AddRss v-if="!search" />
|
||||||
</div>
|
</div>
|
||||||
@ -14,6 +15,7 @@
|
|||||||
import AddRss from '../components/AddRss.vue'
|
import AddRss from '../components/AddRss.vue'
|
||||||
import Magnify from 'vue-material-design-icons/Magnify.vue'
|
import Magnify from 'vue-material-design-icons/Magnify.vue'
|
||||||
import { NcTextField } from '@nextcloud/vue'
|
import { NcTextField } from '@nextcloud/vue'
|
||||||
|
import Search from '../components/Search.vue'
|
||||||
import TopList from '../components/TopList.vue'
|
import TopList from '../components/TopList.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -22,6 +24,7 @@ export default {
|
|||||||
AddRss,
|
AddRss,
|
||||||
Magnify,
|
Magnify,
|
||||||
NcTextField,
|
NcTextField,
|
||||||
|
Search,
|
||||||
TopList,
|
TopList,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
Loading…
Reference in New Issue
Block a user