Skip to content

Commit

Permalink
Add identifiers to channels hidden by ID (FreeTubeApp#4230)
Browse files Browse the repository at this point in the history
* add description option to hiding channels

* does channel id search

* add tag tooltip

* legacy support for hidden channels

* update removeTag

* add parenthesis to id name

* add icon and id checking before requesting

* update id regex

* decouple channel hidden from tags

* update handling for legacy hidden channels

* remove tag description

* formatting

* newline

* shorten retrieving hidden channels

* separate channel api requests

* refractor ft-input-tags.js

* replace secondaryName with preferredName for tags

* unify hidden channel name/icon retrieval function

* remove tooltip from ft-input-tags

* auto update hidden channel if ID was used

* remove hiding channel by name

* i18n channels hidden disabled message

* run auto hidden channel id update once

* Update src/renderer/components/ft-input-tags/ft-input-tags.vue

Co-authored-by: Jason <[email protected]>

* add text selection for ft tags

* add ft-input-tags icon url

* fix icon link

---------

Co-authored-by: Jason <[email protected]>
  • Loading branch information
Benjababe and kommunarr committed Nov 18, 2023
1 parent 6e7cb92 commit a1c660f
Show file tree
Hide file tree
Showing 9 changed files with 256 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import FtSettingsSection from '../ft-settings-section/ft-settings-section.vue'
import FtToggleSwitch from '../ft-toggle-switch/ft-toggle-switch.vue'
import FtInputTags from '../../components/ft-input-tags/ft-input-tags.vue'
import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
import { showToast } from '../../helpers/utils'
import { checkYoutubeId, findChannelTagInfo } from '../../helpers/channels'

export default defineComponent({
name: 'PlayerSettings',
Expand All @@ -13,7 +15,18 @@ export default defineComponent({
'ft-input-tags': FtInputTags,
'ft-flex-box': FtFlexBox,
},
data: function () {
return {
channelHiderDisabled: false,
}
},
computed: {
backendOptions: function () {
return {
preference: this.$store.getters.getBackendPreference,
fallback: this.$store.getters.getBackendFallback
}
},
hideVideoViews: function () {
return this.$store.getters.getHideVideoViews
},
Expand Down Expand Up @@ -92,14 +105,20 @@ export default defineComponent({
hideSubscriptionsLive: function () {
return this.$store.getters.getHideSubscriptionsLive
},
hideSubscriptionsCommunity: function() {
hideSubscriptionsCommunity: function () {
return this.$store.getters.getHideSubscriptionsCommunity
},
showDistractionFreeTitles: function () {
return this.$store.getters.getShowDistractionFreeTitles
},
channelsHidden: function () {
return JSON.parse(this.$store.getters.getChannelsHidden)
return JSON.parse(this.$store.getters.getChannelsHidden).map((ch) => {
// Legacy support
if (typeof ch === 'string') {
return { name: ch, preferredName: '', icon: '' }
}
return ch
})
},
hideSubscriptionsLiveTooltip: function () {
return this.$t('Tooltips.Distraction Free Settings.Hide Subscriptions Live', {
Expand All @@ -109,6 +128,9 @@ export default defineComponent({
})
}
},
mounted: function () {
this.verifyChannelsHidden()
},
methods: {
handleHideRecommendedVideos: function (value) {
if (value) {
Expand All @@ -117,9 +139,51 @@ export default defineComponent({

this.updateHideRecommendedVideos(value)
},
handleInvalidChannel: function () {
showToast(this.$t('Settings.Distraction Free Settings.Hide Channels Invalid'))
},
handleChannelAPIError: function () {
showToast(this.$t('Settings.Distraction Free Settings.Hide Channels API Error'))
},
handleChannelsHidden: function (value) {
this.updateChannelsHidden(JSON.stringify(value))
},
handleChannelsExists: function () {
showToast(this.$t('Settings.Distraction Free Settings.Hide Channels Already Exists'))
},
validateChannelId: function (text) {
return checkYoutubeId(text)
},
findChannelTagInfo: async function (text) {
return await findChannelTagInfo(text, this.backendOptions)
},
verifyChannelsHidden: async function () {
const channelsHiddenCpy = [...this.channelsHidden]

for (let i = 0; i < channelsHiddenCpy.length; i++) {
const tag = this.channelsHidden[i]

// if channel has been processed and confirmed as non existent, skip
if (tag.invalid) continue

// process if no preferred name and is possibly a YouTube ID
if (tag.preferredName === '' && checkYoutubeId(tag.name)) {
this.channelHiderDisabled = true

const { preferredName, icon, iconHref, invalidId } = await this.findChannelTagInfo(tag.name)
if (invalidId) {
channelsHiddenCpy[i] = { name: tag.name, invalid: invalidId }
} else {
channelsHiddenCpy[i] = { name: tag.name, preferredName, icon, iconHref }
}

// update on every tag in case it closes
this.handleChannelsHidden(channelsHiddenCpy)
}
}

this.channelHiderDisabled = false
},

...mapActions([
'updateHideVideoViews',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,12 +230,19 @@
<br class="hide-on-mobile">
<ft-flex-box>
<ft-input-tags
:disabled="channelHiderDisabled"
:disabled-msg="$t('Settings.Distraction Free Settings.Hide Channels Disabled Message')"
:label="$t('Settings.Distraction Free Settings.Hide Channels')"
:placeholder="$t('Settings.Distraction Free Settings.Hide Channels Placeholder')"
:tag-name-placeholder="$t('Settings.Distraction Free Settings.Hide Channels Placeholder')"
:show-action-button="true"
:tag-list="channelsHidden"
:tooltip="$t('Tooltips.Distraction Free Settings.Hide Channels')"
:validate-tag-name="validateChannelId"
:find-tag-info="findChannelTagInfo"
@invalid-name="handleInvalidChannel"
@error-find-tag-info="handleChannelAPIError"
@change="handleChannelsHidden"
@already-exists="handleChannelsExists"
/>
</ft-flex-box>
</ft-settings-section>
Expand Down
23 changes: 20 additions & 3 deletions src/renderer/components/ft-input-tags/ft-input-tags.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,13 @@
inline-size: 60%;
}

.disabledMsg {
color: rgb(233, 255, 108);
padding-block-end: 10px;
}

.ft-tag-box ul {
overflow: auto;
overflow: visible;
display: block;
padding: 0;
margin: 0;
Expand All @@ -19,24 +24,36 @@
background-color: var(--card-bg-color);
margin: 5px;
border-radius: 5px;
display:flex;
display: flex;
float: var(--float-left-ltr-rtl-value);
}

.ft-tag-box li>span {
padding-block: 10px;
padding-inline-start: 10px;
padding-inline: 10px;
overflow-wrap: break-word;
word-wrap: break-word;
word-break: break-all;
hyphens: auto;
user-select: text;
}

.tag-icon {
border-radius: 50%;
block-size: 24px;
vertical-align: middle;
}

.tag-icon-link {
margin: auto;
margin-inline-start: 10px;
}

.removeTagButton {
color: var(--primary-text-color);
opacity: 0.5;
padding: 10px;
padding-inline-start: 0px;
}

.removeTagButton:hover {
Expand Down
57 changes: 42 additions & 15 deletions src/renderer/components/ft-input-tags/ft-input-tags.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
import { defineComponent } from 'vue'
import FtInput from '../ft-input/ft-input.vue'
import FtTooltip from '../ft-tooltip/ft-tooltip.vue'

export default defineComponent({
name: 'FtInputTags',
components: {
'ft-input': FtInput,
'ft-tooltip': FtTooltip
},
props: {
placeholder: {
disabled: {
type: Boolean,
default: false
},
disabledMsg: {
type: String,
default: ''
},
tagNamePlaceholder: {
type: String,
required: true
},
Expand All @@ -28,27 +34,48 @@ export default defineComponent({
tooltip: {
type: String,
default: ''
},
validateTagName: {
type: Function,
default: (_) => true
},
findTagInfo: {
type: Function,
default: (_) => ({ preferredName: '', icon: '' }),
}
},
methods: {
updateTags: function (text, e) {
updateTags: async function (text, _e) {
// text entered add tag and update tag list
const trimmedText = text.trim()
if (!this.tagList.includes(trimmedText)) {
const newList = this.tagList.slice(0)
newList.push(trimmedText)
this.$emit('change', newList)
const name = text.trim()

if (!this.validateTagName(name)) {
this.$emit('invalid-name')
return
}

if (!this.tagList.some((tag) => tag.name === name)) {
// tag info searching allow api calls to be used
const { preferredName, icon, iconHref, err } = await this.findTagInfo(name)

if (err) {
this.$emit('error-find-tag-info')
return
}

const newTag = { name, preferredName, icon, iconHref }
this.$emit('change', [...this.tagList, newTag])
} else {
this.$emit('already-exists')
}

// clear input box
this.$refs.childinput.handleClearTextClick()
this.$refs.tagNameInput.handleClearTextClick()
},
removeTag: function (tag) {
// Remove tag from list
const tagName = tag.trim()
if (this.tagList.includes(tagName)) {
const newList = this.tagList.slice(0)
const index = newList.indexOf(tagName)
newList.splice(index, 1)
if (this.tagList.some((tmpTag) => tmpTag.name === tag.name)) {
const newList = this.tagList.filter((tmpTag) => tmpTag.name !== tag.name)
this.$emit('change', newList)
}
}
Expand Down
26 changes: 22 additions & 4 deletions src/renderer/components/ft-input-tags/ft-input-tags.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,16 @@
<div
class="ft-input-tags-component"
>
<div
v-if="disabled"
class="disabledMsg"
>
{{ disabledMsg }}
</div>
<ft-input
ref="childinput"
:placeholder="placeholder"
ref="tagNameInput"
:disabled="disabled"
:placeholder="tagNamePlaceholder"
:label="label"
:show-label="true"
:tooltip="tooltip"
Expand All @@ -13,15 +20,26 @@
:force-action-button-icon-name="['fas', 'arrow-right']"
@click="updateTags"
/>

<div class="ft-tag-box">
<ul>
<li
v-for="tag in tagList"
:key="tag.id"
>
<span>{{ tag }}</span>
<router-link
v-if="tag.icon"
:to="tag.iconHref ?? ''"
class="tag-icon-link"
>
<img
:src="tag.icon"
alt=""
class="tag-icon"
>
</router-link>
<span>{{ (tag.preferredName) ? tag.preferredName : tag.name }}</span>
<font-awesome-icon
v-if="!disabled"
:icon="['fas', 'fa-times']"
class="removeTagButton"
tabindex="0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,13 @@ export default defineComponent({
// Some component users like channel view will have this disabled
if (!this.useChannelsHiddenPreference) { return [] }

return JSON.parse(this.$store.getters.getChannelsHidden)
return JSON.parse(this.$store.getters.getChannelsHidden).map((ch) => {
// Legacy support
if (typeof ch === 'string') {
return { name: ch, preferredName: '', icon: '' }
}
return ch
})
},
hideUpcomingPremieres: function () {
return this.$store.getters.getHideUpcomingPremieres
Expand Down Expand Up @@ -92,7 +98,7 @@ export default defineComponent({
// hide upcoming
return false
}
if (this.channelsHidden.includes(data.authorId) || this.channelsHidden.includes(data.author)) {
if (this.channelsHidden.some(ch => ch.name === data.authorId) || this.channelsHidden.some(ch => ch.name === data.author)) {
// hide videos by author
return false
}
Expand All @@ -106,7 +112,7 @@ export default defineComponent({
data.author,
data.authorId,
]
if (attrsToCheck.some(a => a != null && this.channelsHidden.includes(a))) {
if (attrsToCheck.some(a => a != null && this.channelsHidden.some(ch => ch.name === a))) {
// hide channels by author
return false
}
Expand All @@ -120,7 +126,7 @@ export default defineComponent({
data.author,
data.authorId,
]
if (attrsToCheck.some(a => a != null && this.channelsHidden.includes(a))) {
if (attrsToCheck.some(a => a != null && this.channelsHidden.some(ch => ch.name === a))) {
// hide playlists by author
return false
}
Expand Down
12 changes: 9 additions & 3 deletions src/renderer/components/ft-list-video-lazy/ft-list-video-lazy.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,18 @@ export default defineComponent({
// Some component users like channel view will have this disabled
if (!this.useChannelsHiddenPreference) { return [] }

return JSON.parse(this.$store.getters.getChannelsHidden)
return JSON.parse(this.$store.getters.getChannelsHidden).map((ch) => {
// Legacy support
if (typeof ch === 'string') {
return { name: ch, preferredName: '', icon: '' }
}
return ch
})
},

shouldBeVisible() {
return !(this.channelsHidden.includes(this.data.authorId) ||
this.channelsHidden.includes(this.data.author))
return !(this.channelsHidden.some(ch => ch.name === this.data.authorId) ||
this.channelsHidden.some(ch => ch.name === this.data.author))
}
},
created() {
Expand Down
Loading

0 comments on commit a1c660f

Please sign in to comment.