mirror of
https://github.com/FreeTubeApp/FreeTube
synced 2024-11-26 11:49:41 +01:00
Merge branch 'development' of github.com:FreeTubeApp/FreeTube into feat/add-select-mode
This commit is contained in:
commit
74f14ea273
@ -11,17 +11,12 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
-webkit-transition: background 0.2s ease-out;
|
|
||||||
-moz-transition: background 0.2s ease-out;
|
|
||||||
-o-transition: background 0.2s ease-out;
|
|
||||||
transition: background 0.2s ease-out;
|
transition: background 0.2s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bubblePadding:hover {
|
.bubblePadding:hover {
|
||||||
background-color: var(--side-nav-hover-color);
|
background-color: var(--side-nav-hover-color);
|
||||||
color: var(--side-nav-hover-text-color);
|
color: var(--side-nav-hover-text-color);
|
||||||
-moz-transition: background 0.2s ease-in;
|
|
||||||
-o-transition: background 0.2s ease-in;
|
|
||||||
transition: background 0.2s ease-in;
|
transition: background 0.2s ease-in;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
}"
|
}"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
role="button"
|
role="button"
|
||||||
|
:aria-expanded="dropdownShown"
|
||||||
@click.stop="handleIconClick"
|
@click.stop="handleIconClick"
|
||||||
@mousedown.stop="handleIconMouseDown"
|
@mousedown.stop="handleIconMouseDown"
|
||||||
@keydown.enter.stop.prevent="handleIconClick"
|
@keydown.enter.stop.prevent="handleIconClick"
|
||||||
@ -34,7 +35,6 @@
|
|||||||
v-if="dropdownOptions.length > 0"
|
v-if="dropdownOptions.length > 0"
|
||||||
class="list"
|
class="list"
|
||||||
role="listbox"
|
role="listbox"
|
||||||
:aria-expanded="dropdownShown"
|
|
||||||
>
|
>
|
||||||
<li
|
<li
|
||||||
v-for="(option, index) in dropdownOptions"
|
v-for="(option, index) in dropdownOptions"
|
||||||
@ -72,7 +72,6 @@
|
|||||||
v-if="dropdownOptions.length > 0"
|
v-if="dropdownOptions.length > 0"
|
||||||
class="list"
|
class="list"
|
||||||
role="listbox"
|
role="listbox"
|
||||||
:aria-expanded="dropdownShown"
|
|
||||||
>
|
>
|
||||||
<li
|
<li
|
||||||
v-for="(option, index) in dropdownOptions"
|
v-for="(option, index) in dropdownOptions"
|
||||||
|
@ -57,8 +57,6 @@
|
|||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
color: var(--primary-text-color);
|
color: var(--primary-text-color);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
-moz-transition: background 0.2s ease-in;
|
|
||||||
-o-transition: background 0.2s ease-in;
|
|
||||||
transition: background 0.2s ease-in;
|
transition: background 0.2s ease-in;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,8 +72,6 @@
|
|||||||
.clearInputTextButton.visible:active {
|
.clearInputTextButton.visible:active {
|
||||||
background-color: var(--tertiary-text-color);
|
background-color: var(--tertiary-text-color);
|
||||||
color: var(--side-nav-active-text-color);
|
color: var(--side-nav-active-text-color);
|
||||||
-moz-transition: background 0.2s ease-in;
|
|
||||||
-o-transition: background 0.2s ease-in;
|
|
||||||
transition: background 0.2s ease-in;
|
transition: background 0.2s ease-in;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,8 +168,6 @@
|
|||||||
.inputAction.enabled:hover {
|
.inputAction.enabled:hover {
|
||||||
background-color: var(--side-nav-hover-color);
|
background-color: var(--side-nav-hover-color);
|
||||||
color: var(--side-nav-hover-text-color);
|
color: var(--side-nav-hover-text-color);
|
||||||
-moz-transition: background 0.2s ease-in;
|
|
||||||
-o-transition: background 0.2s ease-in;
|
|
||||||
transition: background 0.2s ease-in;
|
transition: background 0.2s ease-in;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,8 +178,6 @@
|
|||||||
.inputAction.enabled:active {
|
.inputAction.enabled:active {
|
||||||
background-color: var(--tertiary-text-color);
|
background-color: var(--tertiary-text-color);
|
||||||
color: var(--side-nav-active-text-color);
|
color: var(--side-nav-active-text-color);
|
||||||
-moz-transition: background 0.2s ease-in;
|
|
||||||
-o-transition: background 0.2s ease-in;
|
|
||||||
transition: background 0.2s ease-in;
|
transition: background 0.2s ease-in;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,17 +4,12 @@
|
|||||||
padding-block: 10px 30px;
|
padding-block: 10px 30px;
|
||||||
padding-inline: 10px;
|
padding-inline: 10px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
-webkit-transition: background 0.2s ease-out;
|
|
||||||
-moz-transition: background 0.2s ease-out;
|
|
||||||
-o-transition: background 0.2s ease-out;
|
|
||||||
transition: background 0.2s ease-out;
|
transition: background 0.2s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bubblePadding:hover {
|
.bubblePadding:hover {
|
||||||
background-color: var(--side-nav-hover-color);
|
background-color: var(--side-nav-hover-color);
|
||||||
color: var(--side-nav-hover-text-color);
|
color: var(--side-nav-hover-text-color);
|
||||||
-moz-transition: background 0.2s ease-in;
|
|
||||||
-o-transition: background 0.2s ease-in;
|
|
||||||
transition: background 0.2s ease-in;
|
transition: background 0.2s ease-in;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
inset-block-start: 60px;
|
inset-block-start: 60px;
|
||||||
inset-inline-end: 10px;
|
inset-inline-end: 10px;
|
||||||
min-inline-size: 250px;
|
min-inline-size: 250px;
|
||||||
block-size: 400px;
|
block-size: auto;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
background-color: var(--card-bg-color);
|
background-color: var(--card-bg-color);
|
||||||
box-shadow: 0 0 4px var(--scrollbar-color-hover);
|
box-shadow: 0 0 4px var(--scrollbar-color-hover);
|
||||||
@ -35,24 +35,33 @@
|
|||||||
|
|
||||||
.profileWrapper {
|
.profileWrapper {
|
||||||
margin-block-start: 60px;
|
margin-block-start: 60px;
|
||||||
block-size: 340px;
|
block-size: auto;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
/*
|
||||||
|
profile list max height: 90% of window size - 100 px. It's scaled to be 340px on 800x600 resolution.
|
||||||
|
Offset of 100px is to compensate for the fixed size of elements above the list, which takes more screen space on lower resolutions
|
||||||
|
*/
|
||||||
|
max-block-size: calc(90vh - 100px);
|
||||||
|
min-block-size: 340px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Navbar changes position to horizontal with this media rule.
|
||||||
|
Height adjust for profile list so it won't cover navbar. */
|
||||||
|
@media only screen and (max-width: 680px){
|
||||||
|
.profileWrapper {
|
||||||
|
max-block-size: calc(95vh - 180px);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile {
|
.profile {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
block-size: 50px;
|
block-size: 50px;
|
||||||
-webkit-transition: background 0.2s ease-out;
|
|
||||||
-moz-transition: background 0.2s ease-out;
|
|
||||||
-o-transition: background 0.2s ease-out;
|
|
||||||
transition: background 0.2s ease-out;
|
transition: background 0.2s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile:hover {
|
.profile:hover {
|
||||||
background-color: var(--side-nav-hover-color);
|
background-color: var(--side-nav-hover-color);
|
||||||
color: var(--side-nav-hover-text-color);
|
color: var(--side-nav-hover-text-color);
|
||||||
-moz-transition: background 0.2s ease-in;
|
|
||||||
-o-transition: background 0.2s ease-in;
|
|
||||||
transition: background 0.2s ease-in;
|
transition: background 0.2s ease-in;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,6 +35,10 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
isActiveProfile: function (profile) {
|
||||||
|
return profile._id === this.activeProfile._id
|
||||||
|
},
|
||||||
|
|
||||||
toggleProfileList: function () {
|
toggleProfileList: function () {
|
||||||
this.profileListShown = !this.profileListShown
|
this.profileListShown = !this.profileListShown
|
||||||
|
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
:style="{ background: activeProfile.bgColor, color: activeProfile.textColor }"
|
:style="{ background: activeProfile.bgColor, color: activeProfile.textColor }"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
role="button"
|
role="button"
|
||||||
|
:aria-expanded="profileListShown"
|
||||||
|
aria-controls="profileSelectorList"
|
||||||
@click="toggleProfileList"
|
@click="toggleProfileList"
|
||||||
@mousedown="handleIconMouseDown"
|
@mousedown="handleIconMouseDown"
|
||||||
@keydown.space.prevent="toggleProfileList"
|
@keydown.space.prevent="toggleProfileList"
|
||||||
@ -19,6 +21,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<ft-card
|
<ft-card
|
||||||
v-show="profileListShown"
|
v-show="profileListShown"
|
||||||
|
id="profileSelectorList"
|
||||||
ref="profileList"
|
ref="profileList"
|
||||||
class="profileList"
|
class="profileList"
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
@ -46,7 +49,7 @@
|
|||||||
:key="index"
|
:key="index"
|
||||||
class="profile"
|
class="profile"
|
||||||
:aria-labelledby="'profile-' + index + '-name'"
|
:aria-labelledby="'profile-' + index + '-name'"
|
||||||
aria-selected="false"
|
:aria-selected="isActiveProfile(profile)"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
role="option"
|
role="option"
|
||||||
@click="setActiveProfile(profile)"
|
@click="setActiveProfile(profile)"
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
/* Ensures style here overrides style of .btn */
|
|
||||||
.subscribeButton.btn {
|
|
||||||
align-self: center;
|
|
||||||
block-size: 50%;
|
|
||||||
margin-block-end: 10px;
|
|
||||||
min-inline-size: 150px;
|
|
||||||
white-space: initial;
|
|
||||||
}
|
|
@ -25,29 +25,54 @@ export default defineComponent({
|
|||||||
type: String,
|
type: String,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
|
hideProfileDropdownToggle: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
subscriptionCountText: {
|
subscriptionCountText: {
|
||||||
default: '',
|
default: '',
|
||||||
type: String,
|
type: String,
|
||||||
required: false
|
required: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
isProfileDropdownOpen: false
|
||||||
|
}
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
profileInitials: function () {
|
||||||
|
return this.profileDisplayList.map((profile) => {
|
||||||
|
return profile?.name?.length > 0 ? Array.from(profile.name)[0].toUpperCase() : ''
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
profileList: function () {
|
profileList: function () {
|
||||||
return this.$store.getters.getProfileList
|
return this.$store.getters.getProfileList
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/* sort by 'All Channels' -> active profile -> unsubscribed channels -> subscribed channels */
|
||||||
|
profileDisplayList: function () {
|
||||||
|
const mainProfileAndActiveProfile = [this.profileList[0]]
|
||||||
|
if (this.activeProfile._id !== MAIN_PROFILE_ID) {
|
||||||
|
mainProfileAndActiveProfile.push(this.activeProfile)
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
...mainProfileAndActiveProfile,
|
||||||
|
...this.profileList.filter((profile, i) =>
|
||||||
|
i !== 0 && !this.isActiveProfile(profile) && !this.isProfileSubscribed(profile)),
|
||||||
|
...this.profileList.filter((profile, i) =>
|
||||||
|
i !== 0 && !this.isActiveProfile(profile) && this.isProfileSubscribed(profile))
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
activeProfile: function () {
|
activeProfile: function () {
|
||||||
return this.$store.getters.getActiveProfile
|
return this.$store.getters.getActiveProfile
|
||||||
},
|
},
|
||||||
|
|
||||||
subscriptionInfo: function () {
|
subscriptionInfo: function () {
|
||||||
return this.activeProfile.subscriptions.find((channel) => {
|
return this.subscriptionInfoForProfile(this.activeProfile)
|
||||||
return channel.id === this.channelId
|
|
||||||
}) ?? null
|
|
||||||
},
|
|
||||||
|
|
||||||
isSubscribed: function () {
|
|
||||||
return this.subscriptionInfo !== null
|
|
||||||
},
|
},
|
||||||
|
|
||||||
hideChannelSubscriptions: function () {
|
hideChannelSubscriptions: function () {
|
||||||
@ -55,23 +80,27 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
subscribedText: function () {
|
subscribedText: function () {
|
||||||
let subscribedValue = (this.isSubscribed ? this.$t('Channel.Unsubscribe') : this.$t('Channel.Subscribe')).toUpperCase()
|
let subscribedValue = (this.isProfileSubscribed(this.activeProfile) ? this.$t('Channel.Unsubscribe') : this.$t('Channel.Subscribe')).toUpperCase()
|
||||||
if (this.subscriptionCountText !== '' && !this.hideChannelSubscriptions) {
|
if (this.subscriptionCountText !== '' && !this.hideChannelSubscriptions) {
|
||||||
subscribedValue += ' ' + this.subscriptionCountText
|
subscribedValue += ' ' + this.subscriptionCountText
|
||||||
}
|
}
|
||||||
return subscribedValue
|
return subscribedValue
|
||||||
|
},
|
||||||
|
|
||||||
|
isProfileDropdownEnabled: function () {
|
||||||
|
return !this.hideProfileDropdownToggle && this.profileList.length > 1
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleSubscription: function () {
|
handleSubscription: function (profile = this.activeProfile) {
|
||||||
if (this.channelId === '') {
|
if (this.channelId === '') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentProfile = deepCopy(this.activeProfile)
|
const currentProfile = deepCopy(profile)
|
||||||
|
|
||||||
if (this.isSubscribed) {
|
if (this.isProfileSubscribed(profile)) {
|
||||||
currentProfile.subscriptions = currentProfile.subscriptions.filter((channel) => {
|
currentProfile.subscriptions = currentProfile.subscriptions.filter((channel) => {
|
||||||
return channel.id !== this.channelId
|
return channel.id !== this.channelId
|
||||||
})
|
})
|
||||||
@ -79,16 +108,16 @@ export default defineComponent({
|
|||||||
this.updateProfile(currentProfile)
|
this.updateProfile(currentProfile)
|
||||||
showToast(this.$t('Channel.Channel has been removed from your subscriptions'))
|
showToast(this.$t('Channel.Channel has been removed from your subscriptions'))
|
||||||
|
|
||||||
if (this.activeProfile._id === MAIN_PROFILE_ID) {
|
if (profile._id === MAIN_PROFILE_ID) {
|
||||||
// Check if a subscription exists in a different profile.
|
// Check if a subscription exists in a different profile.
|
||||||
// Remove from there as well.
|
// Remove from there as well.
|
||||||
let duplicateSubscriptions = 0
|
let duplicateSubscriptions = 0
|
||||||
|
|
||||||
this.profileList.forEach((profile) => {
|
this.profileList.forEach((profileInList) => {
|
||||||
if (profile._id === MAIN_PROFILE_ID) {
|
if (profileInList._id === MAIN_PROFILE_ID) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
duplicateSubscriptions += this.unsubscribe(profile, this.channelId)
|
duplicateSubscriptions += this.unsubscribe(profileInList, this.channelId)
|
||||||
})
|
})
|
||||||
|
|
||||||
if (duplicateSubscriptions > 0) {
|
if (duplicateSubscriptions > 0) {
|
||||||
@ -107,7 +136,7 @@ export default defineComponent({
|
|||||||
this.updateProfile(currentProfile)
|
this.updateProfile(currentProfile)
|
||||||
showToast(this.$t('Channel.Added channel to your subscriptions'))
|
showToast(this.$t('Channel.Added channel to your subscriptions'))
|
||||||
|
|
||||||
if (this.activeProfile._id !== MAIN_PROFILE_ID) {
|
if (profile._id !== MAIN_PROFILE_ID) {
|
||||||
const primaryProfile = deepCopy(this.profileList.find(prof => {
|
const primaryProfile = deepCopy(this.profileList.find(prof => {
|
||||||
return prof._id === MAIN_PROFILE_ID
|
return prof._id === MAIN_PROFILE_ID
|
||||||
}))
|
}))
|
||||||
@ -122,6 +151,34 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.isProfileDropdownEnabled && !this.isProfileDropdownOpen) {
|
||||||
|
this.toggleProfileDropdown()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
handleProfileDropdownFocusOut: function () {
|
||||||
|
if (!this.$refs.subscribeButton.matches(':focus-within')) {
|
||||||
|
this.isProfileDropdownOpen = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleProfileDropdown: function() {
|
||||||
|
this.isProfileDropdownOpen = !this.isProfileDropdownOpen
|
||||||
|
},
|
||||||
|
|
||||||
|
isActiveProfile: function (profile) {
|
||||||
|
return profile._id === this.activeProfile._id
|
||||||
|
},
|
||||||
|
|
||||||
|
subscriptionInfoForProfile: function (profile) {
|
||||||
|
return profile.subscriptions.find((channel) => {
|
||||||
|
return channel.id === this.channelId
|
||||||
|
}) ?? null
|
||||||
|
},
|
||||||
|
|
||||||
|
isProfileSubscribed: function (profile) {
|
||||||
|
return this.subscriptionInfoForProfile(profile) !== null
|
||||||
},
|
},
|
||||||
|
|
||||||
unsubscribe: function(profile, channelId) {
|
unsubscribe: function(profile, channelId) {
|
||||||
|
@ -0,0 +1,141 @@
|
|||||||
|
.buttonList {
|
||||||
|
margin: 5px;
|
||||||
|
margin-block-end: 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
block-size: fit-content;
|
||||||
|
box-shadow: 0px 1px 2px rgb(0 0 0 / 50%);
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
/* addresses odd clipping behavior when adjusting window size */
|
||||||
|
background-color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ftSubscribeButton {
|
||||||
|
position: relative;
|
||||||
|
text-align: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensures style here overrides style of .btn */
|
||||||
|
.subscribeButton.btn {
|
||||||
|
min-inline-size: 150px;
|
||||||
|
white-space: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscribeButton.btn, .profileDropdownToggle.btn {
|
||||||
|
align-self: center;
|
||||||
|
margin-block: 0;
|
||||||
|
margin-inline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdownOpened {
|
||||||
|
.subscribeButton, .profileDropdownToggle {
|
||||||
|
border-end-start-radius: 0;
|
||||||
|
border-end-end-radius: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.profileDropdownToggle.btn {
|
||||||
|
border-inline-start: none !important;
|
||||||
|
border-start-start-radius: 0;
|
||||||
|
border-end-start-radius: 0;
|
||||||
|
display: inline-block;
|
||||||
|
min-inline-size: 1em;
|
||||||
|
padding-inline: 10px;
|
||||||
|
box-sizing: content-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hasProfileDropdownToggle {
|
||||||
|
.subscribeButton.btn {
|
||||||
|
min-inline-size: 100px;
|
||||||
|
padding-inline: 5px;
|
||||||
|
border-inline-end: 2px solid var(--primary-color-active) !important;
|
||||||
|
border-start-end-radius: 0;
|
||||||
|
border-end-end-radius: 0;
|
||||||
|
box-sizing: content-box;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.hasProfileDropdownToggle > .subscribeButton.btn, .profileDropdownToggle.btn {
|
||||||
|
padding-block: 5px;
|
||||||
|
padding-inline: 6px;
|
||||||
|
box-shadow: none;
|
||||||
|
flex: auto;
|
||||||
|
block-size: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profileDropdown {
|
||||||
|
background-color: var(--side-nav-color);
|
||||||
|
box-shadow: 0 1px 2px rgb(0 0 0 / 50%);
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
display: inline;
|
||||||
|
font-size: 12px;
|
||||||
|
max-block-size: 200px;
|
||||||
|
margin-block: -10px 0;
|
||||||
|
margin-inline: 5px 0;
|
||||||
|
overflow-y: scroll;
|
||||||
|
position: absolute;
|
||||||
|
text-align: center;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
z-index: 3;
|
||||||
|
// accounts for parent's left and right margins
|
||||||
|
inline-size: calc(100% - 10px);
|
||||||
|
|
||||||
|
.profileList {
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 0;
|
||||||
|
padding-inline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile {
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5em;
|
||||||
|
padding-inline-start: 0.5em;
|
||||||
|
block-size: 50px;
|
||||||
|
align-items: center;
|
||||||
|
transition: background 0.2s ease-out;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--side-nav-hover-color);
|
||||||
|
color: var(--side-nav-hover-text-color);
|
||||||
|
transition: background 0.2s ease-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
.colorOption {
|
||||||
|
inline-size: 40px;
|
||||||
|
block-size: 40px;
|
||||||
|
cursor: pointer;
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
border-radius: 50%;
|
||||||
|
-webkit-border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.initial {
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 1em;
|
||||||
|
text-align: center;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profileName {
|
||||||
|
padding-inline-end: 1em;
|
||||||
|
text-align: start;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.subscribed {
|
||||||
|
background-color: var(--primary-color);
|
||||||
|
|
||||||
|
.profileName {
|
||||||
|
color: var(--text-with-main-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,83 @@
|
|||||||
<template>
|
<template>
|
||||||
<ft-button
|
<div
|
||||||
:label="subscribedText"
|
ref="subscribeButton"
|
||||||
class="subscribeButton"
|
class="ftSubscribeButton"
|
||||||
background-color="var(--primary-color)"
|
:class="{ dropdownOpened: isProfileDropdownOpen}"
|
||||||
text-color="var(--text-with-main-color)"
|
@focusout="handleProfileDropdownFocusOut"
|
||||||
@click="handleSubscription"
|
>
|
||||||
/>
|
<div
|
||||||
|
class="buttonList"
|
||||||
|
:class="{ hasProfileDropdownToggle: isProfileDropdownEnabled}"
|
||||||
|
>
|
||||||
|
<ft-button
|
||||||
|
:label="subscribedText"
|
||||||
|
:no-border="true"
|
||||||
|
class="subscribeButton"
|
||||||
|
background-color="var(--primary-color)"
|
||||||
|
text-color="var(--text-with-main-color)"
|
||||||
|
@click="handleSubscription"
|
||||||
|
/>
|
||||||
|
<ft-button
|
||||||
|
v-if="isProfileDropdownEnabled"
|
||||||
|
:no-border="true"
|
||||||
|
:title="isProfileDropdownOpen ? $t('Profile.Close Profile Dropdown') : $t('Profile.Open Profile Dropdown')"
|
||||||
|
class="profileDropdownToggle"
|
||||||
|
background-color="var(--primary-color)"
|
||||||
|
text-color="var(--text-with-main-color)"
|
||||||
|
:aria-expanded="isProfileDropdownOpen"
|
||||||
|
@click="toggleProfileDropdown"
|
||||||
|
>
|
||||||
|
<font-awesome-icon
|
||||||
|
:icon="isProfileDropdownOpen ? ['fas', 'angle-up'] : ['fas', 'angle-down']"
|
||||||
|
/>
|
||||||
|
</ft-button>
|
||||||
|
</div>
|
||||||
|
<template v-if="isProfileDropdownOpen">
|
||||||
|
<div
|
||||||
|
tabindex="-1"
|
||||||
|
class="profileDropdown"
|
||||||
|
>
|
||||||
|
<ul
|
||||||
|
class="profileList"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
v-for="(profile, index) in profileDisplayList"
|
||||||
|
:id="'subscription-profile-' + index"
|
||||||
|
:key="index"
|
||||||
|
class="profile"
|
||||||
|
:class="{
|
||||||
|
subscribed: isProfileSubscribed(profile)
|
||||||
|
}"
|
||||||
|
:aria-labelledby="'subscription-profile-' + index + '-name'"
|
||||||
|
:aria-selected="isActiveProfile(profile)"
|
||||||
|
:aria-checked="isProfileSubscribed(profile)"
|
||||||
|
tabindex="0"
|
||||||
|
role="checkbox"
|
||||||
|
@click.stop.prevent="handleSubscription(profile)"
|
||||||
|
@keydown.space.stop.prevent="handleSubscription(profile)"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="colorOption"
|
||||||
|
:style="{ background: profile.bgColor, color: profile.textColor }"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="initial"
|
||||||
|
>
|
||||||
|
{{ isProfileSubscribed(profile) ? '✓' : profileInitials[index] }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p
|
||||||
|
:id="'subscription-profile-' + index + '-name'"
|
||||||
|
class="profileName"
|
||||||
|
>
|
||||||
|
{{ profile.name }}
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script src="./ft-subscribe-button.js" />
|
<script src="./ft-subscribe-button.js" />
|
||||||
<style src="./ft-subscribe-button.css" />
|
<style lang="scss" src="./ft-subscribe-button.scss" />
|
||||||
|
@ -14,16 +14,12 @@
|
|||||||
.navOption:hover {
|
.navOption:hover {
|
||||||
background-color: var(--side-nav-hover-color);
|
background-color: var(--side-nav-hover-color);
|
||||||
color: var(--side-nav-hover-text-color);
|
color: var(--side-nav-hover-text-color);
|
||||||
-moz-transition: background 0.2s ease-in;
|
|
||||||
-o-transition: background 0.2s ease-in;
|
|
||||||
transition: background 0.2s ease-in;
|
transition: background 0.2s ease-in;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navOption:active {
|
.navOption:active {
|
||||||
background-color: var(--side-nav-active-color);
|
background-color: var(--side-nav-active-color);
|
||||||
color: var(--side-nav-active-text-color);
|
color: var(--side-nav-active-text-color);
|
||||||
-moz-transition: background 0.2s ease-in;
|
|
||||||
-o-transition: background 0.2s ease-in;
|
|
||||||
transition: background 0.2s ease-in;
|
transition: background 0.2s ease-in;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,16 +53,12 @@
|
|||||||
.navOption:hover, .navChannel:hover {
|
.navOption:hover, .navChannel:hover {
|
||||||
background-color: var(--side-nav-hover-color);
|
background-color: var(--side-nav-hover-color);
|
||||||
color: var(--side-nav-hover-text-color);
|
color: var(--side-nav-hover-text-color);
|
||||||
-moz-transition: background 0.2s ease-in;
|
|
||||||
-o-transition: background 0.2s ease-in;
|
|
||||||
transition: background 0.2s ease-in;
|
transition: background 0.2s ease-in;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navOption:active, .navChannel:active {
|
.navOption:active, .navChannel:active {
|
||||||
background-color: var(--side-nav-active-color);
|
background-color: var(--side-nav-active-color);
|
||||||
color: var(--side-nav-active-text-color);
|
color: var(--side-nav-active-text-color);
|
||||||
-moz-transition: background 0.2s ease-in;
|
|
||||||
-o-transition: background 0.2s ease-in;
|
|
||||||
transition: background 0.2s ease-in;
|
transition: background 0.2s ease-in;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,13 @@
|
|||||||
row-gap: 16px;
|
row-gap: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.watchingCount {
|
||||||
|
font-weight: normal;
|
||||||
|
margin-inline-start: 5px;
|
||||||
|
font-size: 15px;
|
||||||
|
color: var(--tertiary-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
.message {
|
.message {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
color: var(--tertiary-text-color);
|
color: var(--tertiary-text-color);
|
||||||
|
@ -6,6 +6,7 @@ import FtButton from '../ft-button/ft-button.vue'
|
|||||||
import autolinker from 'autolinker'
|
import autolinker from 'autolinker'
|
||||||
import { getRandomColorClass } from '../../helpers/colors'
|
import { getRandomColorClass } from '../../helpers/colors'
|
||||||
import { getLocalVideoInfo, parseLocalTextRuns } from '../../helpers/api/local'
|
import { getLocalVideoInfo, parseLocalTextRuns } from '../../helpers/api/local'
|
||||||
|
import { formatNumber } from '../../helpers/utils'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'WatchVideoLiveChat',
|
name: 'WatchVideoLiveChat',
|
||||||
@ -30,6 +31,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
|
/** @type {import('youtubei.js').YT.LiveChat|null} */
|
||||||
liveChatInstance: null,
|
liveChatInstance: null,
|
||||||
isLoading: true,
|
isLoading: true,
|
||||||
hasError: false,
|
hasError: false,
|
||||||
@ -52,7 +54,9 @@ export default defineComponent({
|
|||||||
amount: '',
|
amount: '',
|
||||||
colorClass: ''
|
colorClass: ''
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
/** @type {number|null} */
|
||||||
|
watchingCount: null,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -74,6 +78,14 @@ export default defineComponent({
|
|||||||
|
|
||||||
scrollingBehaviour: function () {
|
scrollingBehaviour: function () {
|
||||||
return this.$store.getters.getDisableSmoothScrolling ? 'auto' : 'smooth'
|
return this.$store.getters.getDisableSmoothScrolling ? 'auto' : 'smooth'
|
||||||
|
},
|
||||||
|
|
||||||
|
hideVideoViews: function () {
|
||||||
|
return this.$store.getters.getHideVideoViews
|
||||||
|
},
|
||||||
|
|
||||||
|
formattedWatchingCount: function () {
|
||||||
|
return this.watchingCount !== null ? formatNumber(this.watchingCount) : '0'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeDestroy: function () {
|
beforeDestroy: function () {
|
||||||
@ -181,6 +193,12 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.liveChatInstance.on('metadata-update', metadata => {
|
||||||
|
if (!this.hideVideoViews && metadata.views && !isNaN(metadata.views.original_view_count)) {
|
||||||
|
this.watchingCount = metadata.views.original_view_count
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
this.liveChatInstance.once('end', () => {
|
this.liveChatInstance.once('end', () => {
|
||||||
this.hasEnded = true
|
this.hasEnded = true
|
||||||
this.liveChatInstance = null
|
this.liveChatInstance = null
|
||||||
|
@ -42,7 +42,15 @@
|
|||||||
v-else
|
v-else
|
||||||
class="relative"
|
class="relative"
|
||||||
>
|
>
|
||||||
<h4>{{ $t("Video.Live Chat") }}</h4>
|
<h4>
|
||||||
|
{{ $t("Video.Live Chat") }}
|
||||||
|
<span
|
||||||
|
v-if="!hideVideoViews && watchingCount !== null"
|
||||||
|
class="watchingCount"
|
||||||
|
>
|
||||||
|
{{ $tc('Global.Counts.Watching Count', watchingCount, { count: formattedWatchingCount }) }}
|
||||||
|
</span>
|
||||||
|
</h4>
|
||||||
<div
|
<div
|
||||||
v-if="superChatComments.length > 0"
|
v-if="superChatComments.length > 0"
|
||||||
class="superChatComments"
|
class="superChatComments"
|
||||||
|
@ -9,6 +9,7 @@ import { library } from '@fortawesome/fontawesome-svg-core'
|
|||||||
// to avoid code conflict and duplicate entries
|
// to avoid code conflict and duplicate entries
|
||||||
import {
|
import {
|
||||||
faAngleDown,
|
faAngleDown,
|
||||||
|
faAngleUp,
|
||||||
faArrowDown,
|
faArrowDown,
|
||||||
faArrowLeft,
|
faArrowLeft,
|
||||||
faArrowRight,
|
faArrowRight,
|
||||||
@ -82,6 +83,7 @@ Vue.config.productionTip = process.env.NODE_ENV === 'development'
|
|||||||
library.add(
|
library.add(
|
||||||
// solid icons
|
// solid icons
|
||||||
faAngleDown,
|
faAngleDown,
|
||||||
|
faAngleUp,
|
||||||
faArrowDown,
|
faArrowDown,
|
||||||
faArrowLeft,
|
faArrowLeft,
|
||||||
faArrowRight,
|
faArrowRight,
|
||||||
|
@ -69,6 +69,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
gap: 30px;
|
gap: 30px;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.subscribeButton {
|
.subscribeButton {
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
<ft-flex-box class="channels">
|
<ft-flex-box class="channels">
|
||||||
<div
|
<div
|
||||||
v-for="channel in channelList"
|
v-for="channel in channelList"
|
||||||
:key="channel.key"
|
:key="channel.id"
|
||||||
class="channel"
|
class="channel"
|
||||||
>
|
>
|
||||||
<router-link
|
<router-link
|
||||||
@ -53,7 +53,6 @@
|
|||||||
class="unsubscribeContainer"
|
class="unsubscribeContainer"
|
||||||
>
|
>
|
||||||
<ft-subscribe-button
|
<ft-subscribe-button
|
||||||
class="btn"
|
|
||||||
:channel-id="channel.id"
|
:channel-id="channel.id"
|
||||||
:channel-name="channel.name"
|
:channel-name="channel.name"
|
||||||
:channel-thumbnail="channel.thumbnail"
|
:channel-thumbnail="channel.thumbnail"
|
||||||
|
@ -811,6 +811,8 @@ Video:
|
|||||||
'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': الدردشة
|
'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': الدردشة
|
||||||
المباشرة غير متاحة لهذا البث. ربما تم تعطيلها من قبل القائم بالتحميل.
|
المباشرة غير متاحة لهذا البث. ربما تم تعطيلها من قبل القائم بالتحميل.
|
||||||
Pause on Current Video: توقف مؤقتًا على الفيديو الحالي
|
Pause on Current Video: توقف مؤقتًا على الفيديو الحالي
|
||||||
|
Unhide Channel: عرض القناة
|
||||||
|
Hide Channel: إخفاء القناة
|
||||||
Videos:
|
Videos:
|
||||||
#& Sort By
|
#& Sort By
|
||||||
Sort By:
|
Sort By:
|
||||||
@ -1037,3 +1039,6 @@ Playlist will pause when current video is finished: ستتوقف قائمة ال
|
|||||||
انتهاء الفيديو الحالي
|
انتهاء الفيديو الحالي
|
||||||
Playlist will not pause when current video is finished: لن تتوقف قائمة التشغيل مؤقتًا
|
Playlist will not pause when current video is finished: لن تتوقف قائمة التشغيل مؤقتًا
|
||||||
عند انتهاء الفيديو الحالي
|
عند انتهاء الفيديو الحالي
|
||||||
|
Channel Hidden: تم إضافة {channel} إلى مرشح القناة
|
||||||
|
Go to page: إذهب إلى {page}
|
||||||
|
Channel Unhidden: تمت إزالة {channel} من مرشح القناة
|
||||||
|
@ -3,7 +3,7 @@ Locale Name: 'ئیگلیزی (وڵاتە یەکگرتووەکانی ئەمریک
|
|||||||
FreeTube: 'فریتیوب'
|
FreeTube: 'فریتیوب'
|
||||||
# Currently on Subscriptions, Playlists, and History
|
# Currently on Subscriptions, Playlists, and History
|
||||||
'This part of the app is not ready yet. Come back later when progress has been made.': >-
|
'This part of the app is not ready yet. Come back later when progress has been made.': >-
|
||||||
بەشێک لە بەرنامۆچکە هێشتا ئامادە نییە. کە ڕەوتەکە درووست کرا دووبارە وەرەوە.
|
بەشێک لە نەرمەواڵەکە هێشتا ئامادە نییە. کە ڕەوتەکە درووست کرا دووبارە وەرەوە.
|
||||||
|
|
||||||
# Webkit Menu Bar
|
# Webkit Menu Bar
|
||||||
File: 'پەڕگە'
|
File: 'پەڕگە'
|
||||||
@ -32,9 +32,9 @@ Back: 'دواوە'
|
|||||||
Forward: 'پێشەوە'
|
Forward: 'پێشەوە'
|
||||||
Open New Window: 'کردنەوەی پەنجەرەیەکی نوێ'
|
Open New Window: 'کردنەوەی پەنجەرەیەکی نوێ'
|
||||||
|
|
||||||
Version {versionNumber} is now available! Click for more details: 'وەشانی {versionNumber}
|
Version {versionNumber} is now available! Click for more details: 'ئێستا وەشانی {versionNumber}
|
||||||
ئێستا بەردەستە! بۆ زانیاری زۆرتر کرتە بکە'
|
بەردەستە..بۆ زانیاری زۆرتر کرتە بکە'
|
||||||
Download From Site: 'داگرتن لە وێبگە'
|
Download From Site: 'لە وێبگەوە دایگرە'
|
||||||
A new blog is now available, {blogTitle}. Click to view more: ''
|
A new blog is now available, {blogTitle}. Click to view more: ''
|
||||||
Are you sure you want to open this link?: 'دڵنیایت دەتەوێت ئەم بەستەرە بکەیتەوە؟'
|
Are you sure you want to open this link?: 'دڵنیایت دەتەوێت ئەم بەستەرە بکەیتەوە؟'
|
||||||
|
|
||||||
@ -44,13 +44,13 @@ Global:
|
|||||||
Videos: 'ڤیدیۆکان'
|
Videos: 'ڤیدیۆکان'
|
||||||
Shorts: ''
|
Shorts: ''
|
||||||
Live: 'ڕاستەوخۆ'
|
Live: 'ڕاستەوخۆ'
|
||||||
Community: ''
|
Community: 'کۆمەڵگە'
|
||||||
Counts:
|
Counts:
|
||||||
Video Count: '١ ڤیدیۆ | {count} ڤیدیۆ'
|
Video Count: '١ ڤیدیۆ | {count} ڤیدیۆ'
|
||||||
Channel Count: '١ کەناڵ | {count} کەناڵ'
|
Channel Count: '١ کەناڵ | {count} کەناڵ'
|
||||||
Subscriber Count: '١ بەشداربوو | {count} بەشداربوو'
|
Subscriber Count: '١ بەشداربوو | {count} بەشداربوو'
|
||||||
View Count: 'بینینەک | {count} بینین'
|
View Count: 'بینینەک | {count} بینین'
|
||||||
Watching Count: ''
|
Watching Count: '١ تەمەشاکردن | {count} تەمەشاکردن'
|
||||||
|
|
||||||
# Search Bar
|
# Search Bar
|
||||||
Search / Go to URL: ''
|
Search / Go to URL: ''
|
||||||
@ -58,7 +58,7 @@ Search Bar:
|
|||||||
Clear Input: ''
|
Clear Input: ''
|
||||||
# In Filter Button
|
# In Filter Button
|
||||||
Search Filters:
|
Search Filters:
|
||||||
Search Filters: ''
|
Search Filters: 'پاڵفتەکردنی گەڕان'
|
||||||
Sort By:
|
Sort By:
|
||||||
Sort By: 'ڕیزکردن بە'
|
Sort By: 'ڕیزکردن بە'
|
||||||
Most Relevant: ''
|
Most Relevant: ''
|
||||||
@ -87,10 +87,10 @@ Search Filters:
|
|||||||
Medium (4 - 20 minutes): 'ناوەند (٤ - ٢٠ خولەک)'
|
Medium (4 - 20 minutes): 'ناوەند (٤ - ٢٠ خولەک)'
|
||||||
Long (> 20 minutes): 'درێژ (> ٢٠ خولەک)'
|
Long (> 20 minutes): 'درێژ (> ٢٠ خولەک)'
|
||||||
# On Search Page
|
# On Search Page
|
||||||
Search Results: ''
|
Search Results: 'ئەنجامەکانی گەڕان'
|
||||||
Fetching results. Please wait: ''
|
Fetching results. Please wait: ''
|
||||||
Fetch more results: ''
|
Fetch more results: ''
|
||||||
There are no more results for this search: ''
|
There are no more results for this search: 'ئەنجامەکی تر نییە بۆ ئەم گەڕانە'
|
||||||
# Sidebar
|
# Sidebar
|
||||||
Subscriptions:
|
Subscriptions:
|
||||||
# On Subscriptions Page
|
# On Subscriptions Page
|
||||||
@ -121,26 +121,27 @@ Channels:
|
|||||||
Unsubscribe Prompt: ''
|
Unsubscribe Prompt: ''
|
||||||
Trending:
|
Trending:
|
||||||
Trending: ''
|
Trending: ''
|
||||||
Default: ''
|
Default: 'بنەڕەت'
|
||||||
Music: 'مۆسیقا'
|
Music: 'مۆسیقا'
|
||||||
Gaming: 'یاری'
|
Gaming: 'یاری'
|
||||||
Movies: 'فیلم'
|
Movies: 'فیلم'
|
||||||
Trending Tabs: ''
|
Trending Tabs: ''
|
||||||
Most Popular: 'باوترین'
|
Most Popular: 'باوترین'
|
||||||
Playlists: ''
|
Playlists: 'پێڕستی لێدانەکان'
|
||||||
User Playlists:
|
User Playlists:
|
||||||
Your Playlists: ''
|
Your Playlists: 'پێڕستی لێدانەکانت'
|
||||||
Playlist Message: ''
|
Playlist Message: ''
|
||||||
Your saved videos are empty. Click on the save button on the corner of a video to have it listed here: ''
|
Your saved videos are empty. Click on the save button on the corner of a video to have it listed here: ''
|
||||||
Empty Search Message: ''
|
Empty Search Message: ''
|
||||||
Search bar placeholder: ''
|
Search bar placeholder: 'لەناو پێڕستی لێدان بگەڕێ'
|
||||||
History:
|
History:
|
||||||
# On History Page
|
# On History Page
|
||||||
History: 'مێژوو'
|
History: 'مێژوو'
|
||||||
Watch History: 'مێژووی تەمەشاکردن'
|
Watch History: 'مێژووی تەمەشاکردن'
|
||||||
Your history list is currently empty.: ''
|
Your history list is currently empty.: 'ئێستا لیستەی مێژووت بەتاڵە.'
|
||||||
Empty Search Message: ''
|
Empty Search Message: 'هیچ ڤیدیۆیەک لە مێژووت نەدۆزرایەوە کە بەرانبەری گەڕانەکەت
|
||||||
Search bar placeholder: ""
|
بێت'
|
||||||
|
Search bar placeholder: "لەناو مێژوو بگەڕێ"
|
||||||
Settings:
|
Settings:
|
||||||
# On Settings Page
|
# On Settings Page
|
||||||
Settings: 'ڕێکخستنەکان'
|
Settings: 'ڕێکخستنەکان'
|
||||||
@ -153,7 +154,7 @@ Settings:
|
|||||||
Enable Search Suggestions: ''
|
Enable Search Suggestions: ''
|
||||||
Default Landing Page: ''
|
Default Landing Page: ''
|
||||||
Locale Preference: ''
|
Locale Preference: ''
|
||||||
System Default: ''
|
System Default: 'بنەڕەتی سیستەم'
|
||||||
Preferred API Backend:
|
Preferred API Backend:
|
||||||
Preferred API Backend: ''
|
Preferred API Backend: ''
|
||||||
Local API: ''
|
Local API: ''
|
||||||
@ -164,8 +165,8 @@ Settings:
|
|||||||
List: 'پێڕست'
|
List: 'پێڕست'
|
||||||
Thumbnail Preference:
|
Thumbnail Preference:
|
||||||
Thumbnail Preference: ''
|
Thumbnail Preference: ''
|
||||||
Default: ''
|
Default: 'بنەڕەت'
|
||||||
Beginning: ''
|
Beginning: 'سەرەتا'
|
||||||
Middle: 'ناوەڕاست'
|
Middle: 'ناوەڕاست'
|
||||||
End: 'کۆتایی'
|
End: 'کۆتایی'
|
||||||
Hidden: 'شاراوە'
|
Hidden: 'شاراوە'
|
||||||
@ -193,10 +194,10 @@ Settings:
|
|||||||
Hide Side Bar Labels: ''
|
Hide Side Bar Labels: ''
|
||||||
Hide FreeTube Header Logo: ''
|
Hide FreeTube Header Logo: ''
|
||||||
Base Theme:
|
Base Theme:
|
||||||
Base Theme: ''
|
Base Theme: 'ڕووکاری بنچینە'
|
||||||
Black: 'ڕەش'
|
Black: 'ڕەش'
|
||||||
Dark: 'تاریک'
|
Dark: 'تاریک'
|
||||||
System Default: ''
|
System Default: 'بنەڕەتی سیستەم'
|
||||||
Light: 'ڕووناک'
|
Light: 'ڕووناک'
|
||||||
Dracula: ''
|
Dracula: ''
|
||||||
Catppuccin Mocha: ''
|
Catppuccin Mocha: ''
|
||||||
@ -208,11 +209,11 @@ Settings:
|
|||||||
Pink: 'پەمبە'
|
Pink: 'پەمبە'
|
||||||
Purple: 'وەنەوشەیی'
|
Purple: 'وەنەوشەیی'
|
||||||
Deep Purple: 'وەنەوشەیی تۆخ'
|
Deep Purple: 'وەنەوشەیی تۆخ'
|
||||||
Indigo: ''
|
Indigo: 'نیلی'
|
||||||
Blue: 'شین'
|
Blue: 'شین'
|
||||||
Light Blue: 'شینی ئاڵ'
|
Light Blue: 'شینی ئاڵ'
|
||||||
Cyan: ''
|
Cyan: 'شینی تۆخ'
|
||||||
Teal: ''
|
Teal: 'شەدری'
|
||||||
Green: 'کەسک'
|
Green: 'کەسک'
|
||||||
Light Green: 'کەسکی ئاڵ'
|
Light Green: 'کەسکی ئاڵ'
|
||||||
Lime: ''
|
Lime: ''
|
||||||
@ -856,3 +857,4 @@ Hashtag:
|
|||||||
Yes: ''
|
Yes: ''
|
||||||
No: ''
|
No: ''
|
||||||
Ok: ''
|
Ok: ''
|
||||||
|
Go to page: بڕۆ بۆ {page}
|
||||||
|
@ -806,6 +806,8 @@ Video:
|
|||||||
'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Živý
|
'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Živý
|
||||||
chat není pro tento stream k dispozici. Je možné, že byl vypnut nahrávajícím.
|
chat není pro tento stream k dispozici. Je možné, že byl vypnut nahrávajícím.
|
||||||
Pause on Current Video: Pozastavit na současném videu
|
Pause on Current Video: Pozastavit na současném videu
|
||||||
|
Unhide Channel: Zobrazit kanál
|
||||||
|
Hide Channel: Skrýt kanál
|
||||||
Videos:
|
Videos:
|
||||||
#& Sort By
|
#& Sort By
|
||||||
Sort By:
|
Sort By:
|
||||||
@ -1036,3 +1038,6 @@ Playlist will pause when current video is finished: Po přehrání aktuálního
|
|||||||
playlist pozastaven
|
playlist pozastaven
|
||||||
Playlist will not pause when current video is finished: Po přehrání aktuálního videa
|
Playlist will not pause when current video is finished: Po přehrání aktuálního videa
|
||||||
nebude playlist pozastaven
|
nebude playlist pozastaven
|
||||||
|
Channel Hidden: Kanál {channel} přidán do filtru kanálů
|
||||||
|
Go to page: Přejít na {page}
|
||||||
|
Channel Unhidden: Kanál {channel} odebrán z filtrů kanálů
|
||||||
|
@ -554,6 +554,8 @@ Profile:
|
|||||||
Are you sure you want to delete the selected channels? This will not delete the channel from any other profile.: Are
|
Are you sure you want to delete the selected channels? This will not delete the channel from any other profile.: Are
|
||||||
you sure you want to delete the selected channels? This will not delete the channel
|
you sure you want to delete the selected channels? This will not delete the channel
|
||||||
from any other profile.
|
from any other profile.
|
||||||
|
Close Profile Dropdown: Close Profile Dropdown
|
||||||
|
Open Profile Dropdown: Open Profile Dropdown
|
||||||
#On Channel Page
|
#On Channel Page
|
||||||
Channel:
|
Channel:
|
||||||
Subscribe: Subscribe
|
Subscribe: Subscribe
|
||||||
|
@ -827,6 +827,8 @@ Video:
|
|||||||
chat en vivo no está disponible para esta transmisión. Tal vez estaba deshabilitado
|
chat en vivo no está disponible para esta transmisión. Tal vez estaba deshabilitado
|
||||||
antes de la retransmisión.
|
antes de la retransmisión.
|
||||||
Pause on Current Video: Pausa en el vídeo actual
|
Pause on Current Video: Pausa en el vídeo actual
|
||||||
|
Unhide Channel: Mostrar el canal
|
||||||
|
Hide Channel: Ocultar el canal
|
||||||
Videos:
|
Videos:
|
||||||
#& Sort By
|
#& Sort By
|
||||||
Sort By:
|
Sort By:
|
||||||
@ -1073,3 +1075,5 @@ Playlist will pause when current video is finished: La lista de reproducción se
|
|||||||
Playlist will not pause when current video is finished: La lista de reproducción no
|
Playlist will not pause when current video is finished: La lista de reproducción no
|
||||||
se detendrá cuando termine el vídeo actual
|
se detendrá cuando termine el vídeo actual
|
||||||
Go to page: Ir a la {page}
|
Go to page: Ir a la {page}
|
||||||
|
Channel Hidden: '{channel} añadido al filtro de canales'
|
||||||
|
Channel Unhidden: '{channel} eliminado del filtro de canales'
|
||||||
|
@ -764,6 +764,8 @@ Video:
|
|||||||
'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Otsevestlus
|
'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Otsevestlus
|
||||||
pole selle videovoo puhul saadaval. Võib-olla on üleslaadija vestluse keelanud.
|
pole selle videovoo puhul saadaval. Võib-olla on üleslaadija vestluse keelanud.
|
||||||
Pause on Current Video: Peata hetkel esitatav video
|
Pause on Current Video: Peata hetkel esitatav video
|
||||||
|
Unhide Channel: Näita kanalit
|
||||||
|
Hide Channel: Peida kanal
|
||||||
Videos:
|
Videos:
|
||||||
#& Sort By
|
#& Sort By
|
||||||
Sort By:
|
Sort By:
|
||||||
@ -991,3 +993,6 @@ Playlist will pause when current video is finished: Hetkel mängiva video lõppe
|
|||||||
esitusloendi esitamine peatub
|
esitusloendi esitamine peatub
|
||||||
Playlist will not pause when current video is finished: Hetkel mängiva video lõppemisel
|
Playlist will not pause when current video is finished: Hetkel mängiva video lõppemisel
|
||||||
esitusloendi esitamine jätkub
|
esitusloendi esitamine jätkub
|
||||||
|
Channel Hidden: '{channel} on lisatud kanalite filtrisse'
|
||||||
|
Go to page: 'Ava leht: {page}'
|
||||||
|
Channel Unhidden: '{channel} on eemaldatud kanalite filtrist'
|
||||||
|
@ -794,6 +794,8 @@ Video:
|
|||||||
chat dal vivo non è disponibile per questo video. Potrebbe essere stata disattivata
|
chat dal vivo non è disponibile per questo video. Potrebbe essere stata disattivata
|
||||||
dall'autore del caricamento.
|
dall'autore del caricamento.
|
||||||
Pause on Current Video: Pausa sul video attuale
|
Pause on Current Video: Pausa sul video attuale
|
||||||
|
Unhide Channel: Mostra canale
|
||||||
|
Hide Channel: Nascondi canale
|
||||||
Videos:
|
Videos:
|
||||||
#& Sort By
|
#& Sort By
|
||||||
Sort By:
|
Sort By:
|
||||||
@ -1082,3 +1084,6 @@ Playlist will pause when current video is finished: La playlist verrà messa in
|
|||||||
al termine del video attuale
|
al termine del video attuale
|
||||||
Playlist will not pause when current video is finished: La playlist non verrà messa
|
Playlist will not pause when current video is finished: La playlist non verrà messa
|
||||||
in pausa al termine del video attuale
|
in pausa al termine del video attuale
|
||||||
|
Channel Hidden: '{channel} aggiunto al filtro canali'
|
||||||
|
Go to page: Vai a {page}
|
||||||
|
Channel Unhidden: '{channel} rimosso dal filtro canali'
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# Put the name of your locale in the same language
|
# Put the name of your locale in the same language
|
||||||
Locale Name: 'kur-ckb'
|
Locale Name: 'کوردی ناوەڕاست'
|
||||||
FreeTube: 'فریتیوب'
|
FreeTube: 'فریتیوب'
|
||||||
# Currently on Subscriptions, Playlists, and History
|
# Currently on Subscriptions, Playlists, and History
|
||||||
'This part of the app is not ready yet. Come back later when progress has been made.': >-
|
'This part of the app is not ready yet. Come back later when progress has been made.': >-
|
||||||
@ -7,20 +7,20 @@ FreeTube: 'فریتیوب'
|
|||||||
رویداوە.
|
رویداوە.
|
||||||
|
|
||||||
# Webkit Menu Bar
|
# Webkit Menu Bar
|
||||||
File: 'فایل'
|
File: 'پەڕگە'
|
||||||
Quit: 'چونەدەرەوە'
|
Quit: 'دەرچوون'
|
||||||
Edit: 'دەستکاریکردن'
|
Edit: 'دەستکاری'
|
||||||
Undo: 'گەڕانەوە'
|
Undo: 'پووچکردنەوە'
|
||||||
Redo: 'هێنانەوە'
|
Redo: 'هێنانەوە'
|
||||||
Cut: 'بڕین'
|
Cut: 'بڕین'
|
||||||
Copy: 'کۆپی'
|
Copy: 'لەبەرگرتنەوە'
|
||||||
Paste: 'پەیست'
|
Paste: 'لکاندن'
|
||||||
Delete: 'سڕینەوە'
|
Delete: 'سڕینەوە'
|
||||||
Select all: 'دیاریکردنی هەمووی'
|
Select all: 'دیاریکردنی هەمووی'
|
||||||
Reload: 'دوبارە دابەزاندن'
|
Reload: 'بارکردنەوە'
|
||||||
Force Reload: 'دوباری دابەزاندی بەهێز'
|
Force Reload: 'بارکردنەوەی بەزۆر'
|
||||||
Toggle Developer Tools: 'ئەدەواتەکانی دیڤیڵۆپەر بەردەست بخە'
|
Toggle Developer Tools: 'زامنی ئامرازەکانی گەشەپێدەر'
|
||||||
Actual size: 'گەورەیی راستی'
|
Actual size: 'قەبارەی ڕاستەقینە'
|
||||||
Zoom in: 'زووم کردنە ناوەوە'
|
Zoom in: 'زووم کردنە ناوەوە'
|
||||||
Zoom out: 'زووم کردنە دەرەوە'
|
Zoom out: 'زووم کردنە دەرەوە'
|
||||||
Toggle fullscreen: 'شاشەکەت پرکەرەوە'
|
Toggle fullscreen: 'شاشەکەت پرکەرەوە'
|
||||||
@ -30,9 +30,9 @@ Close: 'داخستن'
|
|||||||
Back: 'گەڕانەوە'
|
Back: 'گەڕانەوە'
|
||||||
Forward: 'چونەپێشەوە'
|
Forward: 'چونەپێشەوە'
|
||||||
|
|
||||||
Version {versionNumber} is now available! Click for more details: 'ڤێرژنی {versionNumber}
|
Version {versionNumber} is now available! Click for more details: 'ئێستا وەشانی {versionNumber}
|
||||||
ئێستا بەردەستە! کلیک بکە بۆ زانیاری زیاتر'
|
بەردەستە..بۆ زانیاری زۆرتر کرتە بکە'
|
||||||
Download From Site: 'دایبەزێنە لە سایتەکەوە'
|
Download From Site: 'لە وێبگەوە دایگرە'
|
||||||
A new blog is now available, {blogTitle}. Click to view more: 'بڵۆگێکی نوێ بەردەستە،
|
A new blog is now available, {blogTitle}. Click to view more: 'بڵۆگێکی نوێ بەردەستە،
|
||||||
{blogTitle}. کلیک بکە بۆ بینینی زیاتر'
|
{blogTitle}. کلیک بکە بۆ بینینی زیاتر'
|
||||||
|
|
||||||
@ -190,3 +190,8 @@ Profile:
|
|||||||
Removed {profile} from your profiles: 'سڕاوەتەوە لە پرۆفایلەکانت {profile}'
|
Removed {profile} from your profiles: 'سڕاوەتەوە لە پرۆفایلەکانت {profile}'
|
||||||
Channel:
|
Channel:
|
||||||
Playlists: {}
|
Playlists: {}
|
||||||
|
New Window: پەنجەرەی نوێ
|
||||||
|
Go to page: بڕۆ بۆ {page}
|
||||||
|
Preferences: هەڵبژاردەکان
|
||||||
|
Are you sure you want to open this link?: دڵنیایت دەتەوێت ئەم بەستەرە بکەیتەوە؟
|
||||||
|
Open New Window: کردنەوەی پەنجەرەیەکی نوێ
|
||||||
|
@ -761,6 +761,8 @@ Video:
|
|||||||
YouTube-ом.
|
YouTube-ом.
|
||||||
'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Ћаскање
|
'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': Ћаскање
|
||||||
уживо није доступно за овај стрим. Можда га је онемогућио аутор.
|
уживо није доступно за овај стрим. Можда га је онемогућио аутор.
|
||||||
|
Unhide Channel: Прикажи канал
|
||||||
|
Hide Channel: Сакриј канал
|
||||||
Tooltips:
|
Tooltips:
|
||||||
Subscription Settings:
|
Subscription Settings:
|
||||||
Fetch Feeds from RSS: 'Када је омогућено, FreeTube ће користити RSS уместо свог
|
Fetch Feeds from RSS: 'Када је омогућено, FreeTube ће користити RSS уместо свог
|
||||||
@ -982,3 +984,6 @@ Screenshot Error: Снимак екрана није успео. {error}
|
|||||||
Downloading has completed: „{videoTitle}“ је завршио преузимање
|
Downloading has completed: „{videoTitle}“ је завршио преузимање
|
||||||
Loop is now enabled: Понављање је сада омогућено
|
Loop is now enabled: Понављање је сада омогућено
|
||||||
Downloading failed: Дошло је до проблема при преузимању „{videoTitle}“
|
Downloading failed: Дошло је до проблема при преузимању „{videoTitle}“
|
||||||
|
Channel Hidden: '{channel} је додат на филтер канала'
|
||||||
|
Go to page: Иди на {page}
|
||||||
|
Channel Unhidden: '{channel} је уклоњен из филтера канала'
|
||||||
|
@ -713,6 +713,8 @@ Video:
|
|||||||
Upcoming: 即将到来
|
Upcoming: 即将到来
|
||||||
'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': 实时聊天对此音视频流不可用。上传者可能禁用了它。
|
'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': 实时聊天对此音视频流不可用。上传者可能禁用了它。
|
||||||
Pause on Current Video: 当前视频播完后不自动播放列表中下一视频
|
Pause on Current Video: 当前视频播完后不自动播放列表中下一视频
|
||||||
|
Unhide Channel: 显示频道
|
||||||
|
Hide Channel: 隐藏频道
|
||||||
Videos:
|
Videos:
|
||||||
#& Sort By
|
#& Sort By
|
||||||
Sort By:
|
Sort By:
|
||||||
@ -936,3 +938,5 @@ Hashtag:
|
|||||||
Playlist will pause when current video is finished: 当前视频播完后播放列表会暂停
|
Playlist will pause when current video is finished: 当前视频播完后播放列表会暂停
|
||||||
Playlist will not pause when current video is finished: 当前视频播完后播放列表不会暂停
|
Playlist will not pause when current video is finished: 当前视频播完后播放列表不会暂停
|
||||||
Go to page: 转到页{page}
|
Go to page: 转到页{page}
|
||||||
|
Channel Hidden: '{channel} 频道已添加到频道过滤器'
|
||||||
|
Channel Unhidden: 从频道过滤器删除了{channel} 频道
|
||||||
|
@ -131,7 +131,7 @@ Settings:
|
|||||||
Preferred API Backend:
|
Preferred API Backend:
|
||||||
Preferred API Backend: '偏好API伺服器'
|
Preferred API Backend: '偏好API伺服器'
|
||||||
Local API: '本機 API'
|
Local API: '本機 API'
|
||||||
Invidious API: 'Invidious API(應用程式介面)'
|
Invidious API: 'Invidious API'
|
||||||
Video View Type:
|
Video View Type:
|
||||||
Video View Type: '影片觀看類別'
|
Video View Type: '影片觀看類別'
|
||||||
Grid: '網格'
|
Grid: '網格'
|
||||||
@ -141,7 +141,7 @@ Settings:
|
|||||||
Default: '預設'
|
Default: '預設'
|
||||||
Beginning: '片頭'
|
Beginning: '片頭'
|
||||||
Middle: '中間'
|
Middle: '中間'
|
||||||
End: '結尾'
|
End: '片尾'
|
||||||
Hidden: 隱藏
|
Hidden: 隱藏
|
||||||
Blur: 模糊
|
Blur: 模糊
|
||||||
'Invidious Instance (Default is https://invidious.snopyta.org)': 'Invidious實例(預設為
|
'Invidious Instance (Default is https://invidious.snopyta.org)': 'Invidious實例(預設為
|
||||||
@ -410,7 +410,7 @@ Settings:
|
|||||||
Hide Channels Disabled Message: 某些頻道被使用 ID 封鎖且無法處理。當這些 ID 更新時,功能將會被封鎖
|
Hide Channels Disabled Message: 某些頻道被使用 ID 封鎖且無法處理。當這些 ID 更新時,功能將會被封鎖
|
||||||
Hide Channels Already Exists: 頻道 ID 已存在
|
Hide Channels Already Exists: 頻道 ID 已存在
|
||||||
Hide Channels API Error: 使用提供的 ID 擷取使用者時發生錯誤。請再次檢查 ID 是否正確。
|
Hide Channels API Error: 使用提供的 ID 擷取使用者時發生錯誤。請再次檢查 ID 是否正確。
|
||||||
The app needs to restart for changes to take effect. Restart and apply change?: 此變更需要重啟讓修改生效。重啟並且套用變更?
|
The app needs to restart for changes to take effect. Restart and apply change?: 必須重新啟動應用程式以生效。重新啟動並套用變更嗎?
|
||||||
Proxy Settings:
|
Proxy Settings:
|
||||||
Error getting network information. Is your proxy configured properly?: 取得網路資訊時發生錯誤。您的代理伺服器設定正確嗎?
|
Error getting network information. Is your proxy configured properly?: 取得網路資訊時發生錯誤。您的代理伺服器設定正確嗎?
|
||||||
City: 城市
|
City: 城市
|
||||||
@ -590,12 +590,12 @@ Channel:
|
|||||||
Releases: 發布
|
Releases: 發布
|
||||||
This channel does not currently have any releases: 此頻道目前沒有任何發布
|
This channel does not currently have any releases: 此頻道目前沒有任何發布
|
||||||
Video:
|
Video:
|
||||||
Open in YouTube: '在YouTube中開啟'
|
Open in YouTube: '在 YouTube 中開啟'
|
||||||
Copy YouTube Link: '複製YouTube連結'
|
Copy YouTube Link: '複製 YouTube 連結'
|
||||||
Open YouTube Embedded Player: '開啟YouTube內嵌播放器'
|
Open YouTube Embedded Player: '開啟 YouTube 內嵌播放器'
|
||||||
Copy YouTube Embedded Player Link: '複製YouTube內嵌播放器連結'
|
Copy YouTube Embedded Player Link: '複製 YouTube 內嵌播放器連結'
|
||||||
Open in Invidious: '在Invidious中開啟'
|
Open in Invidious: '在 Invidious 中開啟'
|
||||||
Copy Invidious Link: '複製Invidious連結'
|
Copy Invidious Link: '複製 Invidious 連結'
|
||||||
Views: '觀看'
|
Views: '觀看'
|
||||||
Watched: '已觀看'
|
Watched: '已觀看'
|
||||||
# As in a Live Video
|
# As in a Live Video
|
||||||
@ -661,10 +661,10 @@ Video:
|
|||||||
audio only: 僅音訊
|
audio only: 僅音訊
|
||||||
video only: 僅影片
|
video only: 僅影片
|
||||||
Download Video: 下載影片
|
Download Video: 下載影片
|
||||||
Copy Invidious Channel Link: 複製Invidious頻道連結
|
Copy Invidious Channel Link: 複製 Invidious 頻道連結
|
||||||
Open Channel in Invidious: 在Invidious開啟頻道
|
Open Channel in Invidious: 在 Invidious 開啟頻道
|
||||||
Copy YouTube Channel Link: 複製YouTube頻道連結
|
Copy YouTube Channel Link: 複製 YouTube 頻道連結
|
||||||
Open Channel in YouTube: 在YouTube開啟頻道
|
Open Channel in YouTube: 在 YouTube 開啟頻道
|
||||||
Started streaming on: '開始直播時間'
|
Started streaming on: '開始直播時間'
|
||||||
Streamed on: 直播於
|
Streamed on: 直播於
|
||||||
Video has been removed from your saved list: 影片已從您的播放清單移除
|
Video has been removed from your saved list: 影片已從您的播放清單移除
|
||||||
@ -722,6 +722,8 @@ Video:
|
|||||||
Upcoming: 即將到來
|
Upcoming: 即將到來
|
||||||
'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': 即時聊天在此串流不可用。其可能被上傳者停用了。
|
'Live Chat is unavailable for this stream. It may have been disabled by the uploader.': 即時聊天在此串流不可用。其可能被上傳者停用了。
|
||||||
Pause on Current Video: 暫停目前影片
|
Pause on Current Video: 暫停目前影片
|
||||||
|
Unhide Channel: 顯示頻道
|
||||||
|
Hide Channel: 隱藏頻道
|
||||||
Videos:
|
Videos:
|
||||||
#& Sort By
|
#& Sort By
|
||||||
Sort By:
|
Sort By:
|
||||||
@ -944,3 +946,6 @@ Hashtag:
|
|||||||
This hashtag does not currently have any videos: 此標籤目前沒有任何影片
|
This hashtag does not currently have any videos: 此標籤目前沒有任何影片
|
||||||
Playlist will pause when current video is finished: 當目前影片結束時,播放清單將會暫停
|
Playlist will pause when current video is finished: 當目前影片結束時,播放清單將會暫停
|
||||||
Playlist will not pause when current video is finished: 當目前影片結束時,播放清單將不會暫停
|
Playlist will not pause when current video is finished: 當目前影片結束時,播放清單將不會暫停
|
||||||
|
Channel Hidden: '{channel} 已新增至頻道過濾條件'
|
||||||
|
Go to page: 到 {page}
|
||||||
|
Channel Unhidden: '{channel} 已從頻道過濾條件移除'
|
||||||
|
Loading…
Reference in New Issue
Block a user