Add Search Suggestions and Custom Invidious Instance
This commit is contained in:
parent
2b476f4dc6
commit
c8da6fec3d
|
@ -12940,6 +12940,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz",
|
||||||
"integrity": "sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU="
|
"integrity": "sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU="
|
||||||
},
|
},
|
||||||
|
"lodash.debounce": {
|
||||||
|
"version": "4.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
|
||||||
|
"integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168="
|
||||||
|
},
|
||||||
"lodash.defaults": {
|
"lodash.defaults": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
|
||||||
|
@ -16268,8 +16273,7 @@
|
||||||
},
|
},
|
||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
"resolved": "",
|
||||||
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
|
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"schema-utils": {
|
"schema-utils": {
|
||||||
|
@ -18870,8 +18874,7 @@
|
||||||
},
|
},
|
||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
"resolved": "",
|
||||||
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
|
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"string-width": {
|
"string-width": {
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
"dateformat": "^3.0.3",
|
"dateformat": "^3.0.3",
|
||||||
"electron-context-menu": "^2.0.1",
|
"electron-context-menu": "^2.0.1",
|
||||||
"jquery": "^3.5.1",
|
"jquery": "^3.5.1",
|
||||||
|
"lodash.debounce": "^4.0.8",
|
||||||
"lodash.isequal": "^4.5.0",
|
"lodash.isequal": "^4.5.0",
|
||||||
"material-design-icons": "^3.0.1",
|
"material-design-icons": "^3.0.1",
|
||||||
"mediaelement": "^4.2.16",
|
"mediaelement": "^4.2.16",
|
||||||
|
|
|
@ -22,27 +22,35 @@
|
||||||
color: var(--tertiary-text-color);
|
color: var(--tertiary-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.search .ft-input {
|
.forceTextColor .ft-input {
|
||||||
color: var(--text-with-main-color);
|
color: var(--text-with-main-color);
|
||||||
border-bottom: 1px solid var(--text-with-main-color);
|
border-bottom: 1px solid var(--text-with-main-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.search ::-webkit-input-placeholder {
|
.forceTextColor ::-webkit-input-placeholder {
|
||||||
color: var(--text-with-main-color);
|
color: var(--text-with-main-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.inputAction {
|
.inputAction {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
top: 10px;
|
top: 5px;
|
||||||
right: 0px;
|
right: 0px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-radius: 200px 200px 200px 200px;
|
border-radius: 200px 200px 200px 200px;
|
||||||
color: var(--primary-text-color);
|
color: var(--primary-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search ::-webkit-calendar-picker-indicator {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.search .inputAction {
|
.search .inputAction {
|
||||||
color: var(--text-with-main-color)
|
top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.forceTextColor .inputAction {
|
||||||
|
color: var(--text-with-main-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.inputAction:hover {
|
.inputAction:hover {
|
||||||
|
@ -52,7 +60,7 @@
|
||||||
transition: background 0.2s ease-in;
|
transition: background 0.2s ease-in;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search .inputAction:hover {
|
.forceTextColor .inputAction:hover {
|
||||||
background-color: var(--primary-color-hover);
|
background-color: var(--primary-color-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,6 +71,6 @@
|
||||||
transition: background 0.2s ease-in;
|
transition: background 0.2s ease-in;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search .inputAction:active {
|
.forceTextColor .inputAction:active {
|
||||||
background-color: var(--primary-color-active);
|
background-color: var(--primary-color-active);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,14 +7,26 @@ export default Vue.extend({
|
||||||
type: String,
|
type: String,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
showArrow: {
|
showArrow: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
},
|
},
|
||||||
|
showLabel: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
isSearch: {
|
isSearch: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
}
|
},
|
||||||
|
dataList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => { return [] }
|
||||||
|
},
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
|
@ -29,6 +41,10 @@ export default Vue.extend({
|
||||||
|
|
||||||
forceTextColor: function () {
|
forceTextColor: function () {
|
||||||
return this.isSearch && this.barColor
|
return this.isSearch && this.barColor
|
||||||
|
},
|
||||||
|
|
||||||
|
idDataList: function () {
|
||||||
|
return `${this.id}_datalist`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
|
@ -41,6 +57,11 @@ export default Vue.extend({
|
||||||
this.$emit('click', this.inputData)
|
this.$emit('click', this.inputData)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handleInput: function (input) {
|
||||||
|
this.inputData = input
|
||||||
|
this.$emit('input', input)
|
||||||
|
},
|
||||||
|
|
||||||
addListener: function () {
|
addListener: function () {
|
||||||
const inputElement = document.getElementById(this.id)
|
const inputElement = document.getElementById(this.id)
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,25 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="ft-input-component"
|
class="ft-input-component"
|
||||||
:class="{ search: forceTextColor }"
|
:class="{
|
||||||
|
search: isSearch,
|
||||||
|
forceTextColor: forceTextColor
|
||||||
|
}"
|
||||||
>
|
>
|
||||||
|
<label
|
||||||
|
v-if="showLabel"
|
||||||
|
:for="id"
|
||||||
|
>
|
||||||
|
{{ placeholder }}
|
||||||
|
</label>
|
||||||
<input
|
<input
|
||||||
:id="id"
|
:id="id"
|
||||||
|
:list="idDataList"
|
||||||
|
:value="value"
|
||||||
class="ft-input"
|
class="ft-input"
|
||||||
type="text"
|
type="text"
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
@input="e => inputData = e.target.value"
|
@input="e => handleInput(e.target.value)"
|
||||||
>
|
>
|
||||||
<font-awesome-icon
|
<font-awesome-icon
|
||||||
v-if="showArrow"
|
v-if="showArrow"
|
||||||
|
@ -16,6 +27,16 @@
|
||||||
class="inputAction"
|
class="inputAction"
|
||||||
@click="handleClick"
|
@click="handleClick"
|
||||||
/>
|
/>
|
||||||
|
<datalist
|
||||||
|
v-if="dataList.length > 0"
|
||||||
|
:id="idDataList"
|
||||||
|
>
|
||||||
|
<option
|
||||||
|
v-for="(list, index) in dataList"
|
||||||
|
:key="index"
|
||||||
|
:value="list"
|
||||||
|
/>
|
||||||
|
</datalist>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -3,14 +3,18 @@ import $ from 'jquery'
|
||||||
import { mapActions } from 'vuex'
|
import { mapActions } from 'vuex'
|
||||||
import FtCard from '../ft-card/ft-card.vue'
|
import FtCard from '../ft-card/ft-card.vue'
|
||||||
import FtSelect from '../ft-select/ft-select.vue'
|
import FtSelect from '../ft-select/ft-select.vue'
|
||||||
|
import FtInput from '../ft-input/ft-input.vue'
|
||||||
import FtToggleSwitch from '../ft-toggle-switch/ft-toggle-switch.vue'
|
import FtToggleSwitch from '../ft-toggle-switch/ft-toggle-switch.vue'
|
||||||
import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
|
import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
|
||||||
|
|
||||||
|
import debounce from 'lodash.debounce'
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
name: 'GeneralSettings',
|
name: 'GeneralSettings',
|
||||||
components: {
|
components: {
|
||||||
'ft-card': FtCard,
|
'ft-card': FtCard,
|
||||||
'ft-select': FtSelect,
|
'ft-select': FtSelect,
|
||||||
|
'ft-input': FtInput,
|
||||||
'ft-toggle-switch': FtToggleSwitch,
|
'ft-toggle-switch': FtToggleSwitch,
|
||||||
'ft-flex-box': FtFlexBox
|
'ft-flex-box': FtFlexBox
|
||||||
},
|
},
|
||||||
|
@ -597,8 +601,20 @@ export default Vue.extend({
|
||||||
console.log(requestUrl)
|
console.log(requestUrl)
|
||||||
console.log(error)
|
console.log(error)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.updateInvidiousInstanceBounce = debounce(this.updateInvidiousInstance, 500)
|
||||||
|
},
|
||||||
|
beforeDestroy: function () {
|
||||||
|
if (this.invidiousInstance === '') {
|
||||||
|
this.updateInvidiousInstance('https://invidio.us')
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
handleInvidiousInstanceInput: function (input) {
|
||||||
|
const invidiousInstance = input.replace(/\/$/, '')
|
||||||
|
this.updateInvidiousInstanceBounce(invidiousInstance)
|
||||||
|
},
|
||||||
|
|
||||||
...mapActions([
|
...mapActions([
|
||||||
'updateBackendFallback',
|
'updateBackendFallback',
|
||||||
'updateCheckForUpdates',
|
'updateCheckForUpdates',
|
||||||
|
|
|
@ -57,15 +57,17 @@
|
||||||
:select-values="thumbnailTypeValues"
|
:select-values="thumbnailTypeValues"
|
||||||
@change="updateThumbnailPreference"
|
@change="updateThumbnailPreference"
|
||||||
/>
|
/>
|
||||||
<ft-select
|
|
||||||
v-if="showInvidiousInstances"
|
|
||||||
placeholder="Invidious Instance"
|
|
||||||
:value="invidiousInstance"
|
|
||||||
:select-names="instanceNames"
|
|
||||||
:select-values="instanceValues"
|
|
||||||
@change="updateInvidiousInstance"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
<ft-flex-box class="generalSettingsFlexBox">
|
||||||
|
<ft-input
|
||||||
|
placeholder="Invidious Instance (Default is https://invidio.us)"
|
||||||
|
:show-arrow="false"
|
||||||
|
:show-label="true"
|
||||||
|
:value="invidiousInstance"
|
||||||
|
:data-list="instanceValues"
|
||||||
|
@input="handleInvidiousInstanceInput"
|
||||||
|
/>
|
||||||
|
</ft-flex-box>
|
||||||
</ft-card>
|
</ft-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@ import FtInput from '../ft-input/ft-input.vue'
|
||||||
import FtSearchFilters from '../ft-search-filters/ft-search-filters.vue'
|
import FtSearchFilters from '../ft-search-filters/ft-search-filters.vue'
|
||||||
import $ from 'jquery'
|
import $ from 'jquery'
|
||||||
import router from '../../router/index.js'
|
import router from '../../router/index.js'
|
||||||
|
import debounce from 'lodash.debounce'
|
||||||
|
import ytSuggest from 'youtube-suggest'
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
name: 'TopNav',
|
name: 'TopNav',
|
||||||
|
@ -14,7 +16,9 @@ export default Vue.extend({
|
||||||
return {
|
return {
|
||||||
component: this,
|
component: this,
|
||||||
windowWidth: 0,
|
windowWidth: 0,
|
||||||
showFilters: false
|
showFilters: false,
|
||||||
|
searchValue: '',
|
||||||
|
searchSuggestionsDataList: []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -28,7 +32,19 @@ export default Vue.extend({
|
||||||
|
|
||||||
barColor: function () {
|
barColor: function () {
|
||||||
return this.$store.getters.getBarColor
|
return this.$store.getters.getBarColor
|
||||||
}
|
},
|
||||||
|
|
||||||
|
invidiousInstance: function () {
|
||||||
|
return this.$store.getters.getInvidiousInstance
|
||||||
|
},
|
||||||
|
|
||||||
|
backendFallback: function () {
|
||||||
|
return this.$store.getters.getBackendFallback
|
||||||
|
},
|
||||||
|
|
||||||
|
backendPreference: function () {
|
||||||
|
return this.$store.getters.getBackendPreference
|
||||||
|
},
|
||||||
},
|
},
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
const appWidth = $(window).width()
|
const appWidth = $(window).width()
|
||||||
|
@ -48,6 +64,8 @@ export default Vue.extend({
|
||||||
searchContainer.style.display = 'none'
|
searchContainer.style.display = 'none'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.debounceSearchResults = debounce(this.getSearchSuggestions, 500)
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
goToSearch: function (query) {
|
goToSearch: function (query) {
|
||||||
|
@ -84,6 +102,55 @@ export default Vue.extend({
|
||||||
this.showFilters = false
|
this.showFilters = false
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getSearchSuggestionsDebounce: function (query) {
|
||||||
|
this.debounceSearchResults(query)
|
||||||
|
},
|
||||||
|
|
||||||
|
getSearchSuggestions: function (query) {
|
||||||
|
switch (this.backendPreference) {
|
||||||
|
case 'local':
|
||||||
|
this.getSearchSuggestionsLocal(query)
|
||||||
|
break
|
||||||
|
case 'invidious':
|
||||||
|
this.getSearchSuggestionsInvidious(query)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getSearchSuggestionsLocal: function (query) {
|
||||||
|
if (query === '') {
|
||||||
|
this.searchSuggestionsDataList = []
|
||||||
|
this.searchValue = ''
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ytSuggest(query).then((results) => {
|
||||||
|
this.searchSuggestionsDataList = results
|
||||||
|
this.searchValue = query
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
getSearchSuggestionsInvidious: function (query) {
|
||||||
|
if (query === '') {
|
||||||
|
this.searchSuggestionsDataList = []
|
||||||
|
this.searchValue = ''
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const searchPayload = {
|
||||||
|
resource: 'search/suggestions',
|
||||||
|
id: '',
|
||||||
|
params: {
|
||||||
|
q: query
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$store.dispatch('invidiousAPICall', searchPayload).then((results) => {
|
||||||
|
this.searchSuggestionsDataList = results.suggestions
|
||||||
|
this.searchValue = query
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
toggleSearchContainer: function () {
|
toggleSearchContainer: function () {
|
||||||
const searchContainer = $('.searchContainer').get(0)
|
const searchContainer = $('.searchContainer').get(0)
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,9 @@
|
||||||
placeholder="Search / Go to URL"
|
placeholder="Search / Go to URL"
|
||||||
class="searchInput"
|
class="searchInput"
|
||||||
:is-search="true"
|
:is-search="true"
|
||||||
|
:data-list="searchSuggestionsDataList"
|
||||||
|
:value="searchValue"
|
||||||
|
@input="getSearchSuggestionsDebounce"
|
||||||
@click="goToSearch"
|
@click="goToSearch"
|
||||||
/>
|
/>
|
||||||
<font-awesome-icon
|
<font-awesome-icon
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
.channelInformation {
|
.channelInformation {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 10px;
|
bottom: 10px;
|
||||||
width: 300px;
|
width: 350px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.channelThumbnail {
|
.channelThumbnail {
|
||||||
|
|
|
@ -150,14 +150,18 @@ const getters = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
grabUserSettings ({ commit }) {
|
grabUserSettings ({ dispatch, commit }) {
|
||||||
settingsDb.find({}, (err, results) => {
|
settingsDb.find({}, (err, results) => {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
console.log(results)
|
console.log(results)
|
||||||
results.forEach((result) => {
|
results.forEach((result) => {
|
||||||
switch (result._id) {
|
switch (result._id) {
|
||||||
case 'invidiousInstance':
|
case 'invidiousInstance':
|
||||||
|
if (result.value === '') {
|
||||||
|
dispatch('updateInvidiousInstance', 'https://invidio.us')
|
||||||
|
} else {
|
||||||
commit('setInvidiousInstance', result.value)
|
commit('setInvidiousInstance', result.value)
|
||||||
|
}
|
||||||
break
|
break
|
||||||
case 'backendFallback':
|
case 'backendFallback':
|
||||||
commit('setBackendFallback', result.value)
|
commit('setBackendFallback', result.value)
|
||||||
|
|
|
@ -137,6 +137,7 @@ export default Vue.extend({
|
||||||
this.videoId = this.$route.params.id
|
this.videoId = this.$route.params.id
|
||||||
|
|
||||||
this.firstLoad = true
|
this.firstLoad = true
|
||||||
|
this.activeFormat = this.defaultVideoFormat
|
||||||
|
|
||||||
this.checkIfPlaylist()
|
this.checkIfPlaylist()
|
||||||
|
|
||||||
|
@ -206,6 +207,16 @@ export default Vue.extend({
|
||||||
this.videoDislikeCount = result.dislikes
|
this.videoDislikeCount = result.dislikes
|
||||||
this.isLive = result.player_response.videoDetails.isLive
|
this.isLive = result.player_response.videoDetails.isLive
|
||||||
|
|
||||||
|
const subCount = result.author.subscriber_count
|
||||||
|
|
||||||
|
if (subCount >= 1000000) {
|
||||||
|
this.channelSubscriptionCountText = `${subCount / 1000000}M`
|
||||||
|
} else if (subCount >= 10000) {
|
||||||
|
this.channelSubscriptionCountText = `${subCount / 1000}K`
|
||||||
|
} else {
|
||||||
|
this.channelSubscriptionCountText = subCount.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
||||||
|
}
|
||||||
|
|
||||||
if (this.isLive) {
|
if (this.isLive) {
|
||||||
this.showLegacyPlayer = true
|
this.showLegacyPlayer = true
|
||||||
this.showDashPlayer = false
|
this.showDashPlayer = false
|
||||||
|
|
Loading…
Reference in New Issue