1
0
mirror of https://github.com/TeamPiped/Piped.git synced 2024-12-13 13:50:27 +05:30
This commit is contained in:
Bnyro 2022-09-08 23:11:12 +02:00
commit c8d7ceaea4
36 changed files with 1046 additions and 362 deletions

View File

@ -18,7 +18,7 @@ jobs:
cache: "yarn" cache: "yarn"
- run: yarn install --prefer-offline - run: yarn install --prefer-offline
- run: yarn build && sed -i 's/fonts.gstatic.com/fonts.kavin.rocks/g' dist/assets/*.css && cp dist/index.html dist/ipfs-404.html - run: yarn build && sed -i 's/fonts.gstatic.com/fonts.kavin.rocks/g' dist/assets/*.css && cp dist/index.html dist/ipfs-404.html
- uses: aquiladev/ipfs-action@v0.3.0-alpha.1 - uses: aquiladev/ipfs-action@v0.3.1-alpha.2
id: ipfs-add id: ipfs-add
with: with:
path: ./dist path: ./dist

View File

@ -127,7 +127,8 @@ Contributions in any other form are also welcomed.
# Made with Piped # Made with Piped
- [Yattee](https://github.com/yattee/yattee) - an alternative frontend for YouTube, for IOS. - [Yattee](https://github.com/yattee/yattee) - an alternative frontend for YouTube, for IOS.
- [LibreTube](https://github.com/Libre-tube/LibreTube) [WIP] - an alternative frontend for YouTube, for Android. - [LibreTube](https://github.com/Libre-tube/LibreTube) - an alternative frontend for YouTube, for Android.
- [Hyperpipe](https://codeberg.org/Hyperpipe/Hyperpipe) - an alternative privacy respecting frontend for YouTube Music.
## YourKit ## YourKit

View File

@ -9,37 +9,42 @@
"lint": "eslint --fix --color --ignore-path .gitignore --ext .js,.vue ." "lint": "eslint --fix --color --ignore-path .gitignore --ext .js,.vue ."
}, },
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.1.2", "@fortawesome/fontawesome-svg-core": "^6.2.0",
"@fortawesome/free-brands-svg-icons": "^6.1.2", "@fortawesome/free-brands-svg-icons": "^6.2.0",
"@fortawesome/free-solid-svg-icons": "^6.1.2", "@fortawesome/free-solid-svg-icons": "^6.2.0",
"@fortawesome/vue-fontawesome": "^3.0.1", "@fortawesome/vue-fontawesome": "^3.0.1",
"buffer": "^6.0.3", "buffer": "^6.0.3",
"dompurify": "^2.3.12", "dompurify": "^2.4.0",
"hotkeys-js": "^3.9.4", "hotkeys-js": "^3.10.0",
"javascript-time-ago": "^2.5.7", "javascript-time-ago": "^2.5.7",
"mux.js": "^6.2.0", "mux.js": "^6.2.0",
"shaka-player": "4.2.0", "shaka-player": "4.2.1",
"stream": "^0.0.2", "stream": "^0.0.2",
"vue": "^3.2.37", "vue": "^3.2.38",
"vue-i18n": "^9.2.2", "vue-i18n": "^9.2.2",
"vue-router": "^4.1.4", "vue-router": "^4.1.5",
"xml-js": "^1.6.11" "xml-js": "^1.6.11"
}, },
"devDependencies": { "devDependencies": {
"@iconify/json": "^2.1.103",
"@intlify/vite-plugin-vue-i18n": "^6.0.1", "@intlify/vite-plugin-vue-i18n": "^6.0.1",
"@unocss/preset-icons": "^0.45.13",
"@unocss/preset-web-fonts": "^0.45.7",
"@unocss/transformer-directives": "^0.45.7",
"@unocss/transformer-variant-group": "^0.45.13",
"@vitejs/plugin-legacy": "^1.8.2", "@vitejs/plugin-legacy": "^1.8.2",
"@vitejs/plugin-vue": "^2.3.4", "@vitejs/plugin-vue": "^2.3.4",
"@vue/compiler-sfc": "3.2.37", "@vue/compiler-sfc": "3.2.38",
"babel-eslint": "^10.1.0", "babel-eslint": "^10.1.0",
"eslint": "^7.32.0", "eslint": "^7.32.0",
"eslint-config-prettier": "^8.5.0", "eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.2.1", "eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-vue": "^9.3.0", "eslint-plugin-vue": "^9.4.0",
"prettier": "^2.7.1", "prettier": "^2.7.1",
"unocss": "^0.45.18",
"vite": "^2.9.14", "vite": "^2.9.14",
"vite-plugin-eslint": "^1.7.0", "vite-plugin-eslint": "^1.8.1",
"vite-plugin-pwa": "^0.12.3", "vite-plugin-pwa": "^0.12.7"
"vite-plugin-windicss": "^1.8.7"
}, },
"eslintConfig": { "eslintConfig": {
"root": true, "root": true,

View File

@ -102,11 +102,11 @@ b {
} }
.video-grid { .video-grid {
@apply grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 col-auto <md:gap-x-2.5 md:gap-x-1vw gap-y-1.5; @apply grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 col-auto lt-md:gap-x-2.5 md:gap-x-1vw gap-y-1.5;
} }
.btn { .btn {
@apply h-full py-2 <md:(px-2) md:(px-4) rounded cursor-pointer; @apply h-full py-2 lt-md:px-2 md:px-4 rounded cursor-pointer;
} }
.reset { .reset {
@ -114,7 +114,7 @@ b {
} }
.auto { .auto {
@apply dark:(text-white bg-dark-900); @apply @dark:(text-white bg-dark-900);
} }
.dark { .dark {
@ -145,13 +145,18 @@ b {
.auto .input, .auto .input,
.auto .select, .auto .select,
.auto .btn { .auto .btn {
@apply dark:(text-gray-400 bg-dark-400); @apply @dark:(text-gray-400 bg-dark-400);
} }
.input { .input {
@apply pl-2.5; @apply pl-2.5;
} }
.input:focus {
@apply border-2 border-red-500 outline-none;
box-shadow: 0 0 15px rgba(239, 68, 68, var(--un-border-opacity));
}
hr { hr {
@apply !mt-2 !mb-3 border-gray-300; @apply !mt-2 !mb-3 border-gray-300;
} }
@ -161,7 +166,7 @@ hr {
} }
.auto hr { .auto hr {
@apply dark:border-dark-100; @apply @dark:border-dark-100;
} }
h1, h1,
@ -194,7 +199,7 @@ h2 {
} }
.auto .link { .auto .link {
@apply dark:hover:(text-gray-300 underline underline-gray-300); @apply @dark:hover:(text-gray-300 underline underline-gray-300);
} }
.dark .link-secondary { .dark .link-secondary {
@ -202,7 +207,7 @@ h2 {
} }
.auto .link-secondary { .auto .link-secondary {
@apply dark:(text-gray-300 hover:(text-gray-400 underline underline-gray-400)); @apply @dark:(text-gray-300 hover:(text-gray-400 underline underline-gray-400));
} }
.line { .line {

View File

@ -1,6 +1,6 @@
<template> <template>
<!-- desktop view --> <!-- desktop view -->
<div v-if="!mobileLayout" class="flex-col overflow-y-scroll max-h-75vh min-h-64 <lg:hidden"> <div v-if="!mobileLayout" class="flex-col overflow-y-scroll max-h-75vh min-h-64 lt-lg:hidden">
<h2 class="mb-2 bg-gray-500/50 p-2" aria-label="chapters" title="chapters"> <h2 class="mb-2 bg-gray-500/50 p-2" aria-label="chapters" title="chapters">
{{ $t("video.chapters") }} ({{ chapters.length }}) {{ $t("video.chapters") }} ({{ chapters.length }})
</h2> </h2>
@ -45,16 +45,17 @@
} }
.chapter { .chapter {
@apply cursor-pointer self-center p-2.5; @apply cursor-pointer self-center p-2.5;
img { }
@apply w-full h-full; .chapter img {
} @apply w-full h-full;
} }
.chapter-vertical { .chapter-vertical {
@apply cursor-pointer self-center p-2.5; @apply cursor-pointer self-center p-2.5;
img {
@apply w-3/10 h-3/10;
}
} }
.chapter-vertical img {
@apply w-3/10 h-3/10;
}
.chapter-vertical:hover { .chapter-vertical:hover {
@apply bg-gray-500; @apply bg-gray-500;
} }

View File

@ -24,8 +24,8 @@
<div class="comment-meta text-sm mb-1.5" v-text="comment.commentedTime" /> <div class="comment-meta text-sm mb-1.5" v-text="comment.commentedTime" />
</div> </div>
<div class="whitespace-pre-wrap" v-text="comment.commentText" /> <div class="whitespace-pre-wrap" v-text="comment.commentText" />
<div class="comment-footer mt-1"> <div class="comment-footer mt-1 flex">
<font-awesome-icon icon="thumbs-up" /> <div class="i-fa-solid:thumbs-up" />
<span class="ml-1" v-text="numberFormat(comment.likeCount)" /> <span class="ml-1" v-text="numberFormat(comment.likeCount)" />
<font-awesome-icon class="ml-1" v-if="comment.hearted" icon="heart" /> <font-awesome-icon class="ml-1" v-if="comment.hearted" icon="heart" />
</div> </div>

View File

@ -0,0 +1,42 @@
<template>
<div class="modal">
<div>
<div class="modal-container">
<slot></slot>
</div>
</div>
</div>
</template>
<script>
export default {
mounted() {
window.addEventListener("keydown", this.handleKeyDown);
},
unmounted() {
window.removeEventListener("keydown", this.handleKeyDown);
},
methods: {
handleKeyDown(event) {
if (event.code === "Escape") {
this.$emit("close");
} else return;
event.preventDefault();
},
},
};
</script>
<style scoped>
.modal {
@apply fixed z-50 top-0 left-0 w-full h-full bg-dark-900 bg-opacity-80 transition-opacity table;
}
.modal > div {
@apply table-cell align-middle;
}
.modal-container {
@apply w-min m-auto px-8 bg-dark-700 p-6 rounded-xl min-w-[20vw];
}
</style>

View File

@ -1,7 +1,7 @@
<template> <template>
<nav class="flex flex-wrap items-center justify-center px-2 sm:px-4 py-2.5 w-full relative"> <nav class="flex flex-wrap items-center justify-center px-2 sm:px-4 py-2.5 w-full relative">
<div class="flex-1 flex justify-start"> <div class="flex-1 flex justify-start">
<router-link class="flex font-bold text-3xl items-center font-sans font-bold" to="/" <router-link class="flex font-bold text-3xl items-center font-sans" to="/"
><img ><img
alt="logo" alt="logo"
src="/img/icons/logo.svg" src="/img/icons/logo.svg"
@ -11,10 +11,10 @@
/>iped</router-link />iped</router-link
> >
</div> </div>
<div class="<md:hidden"> <div class="lt-md:hidden">
<input <input
v-model="searchText" v-model="searchText"
class="input !w-72 !h-10" class="input w-72 h-10"
type="text" type="text"
role="search" role="search"
ref="videoSearch" ref="videoSearch"
@ -89,7 +89,7 @@
<div class="w-{full - 4} md:hidden mx-2"> <div class="w-{full - 4} md:hidden mx-2">
<input <input
v-model="searchText" v-model="searchText"
class="input !h-10 !w-full" class="input h-10 w-full"
type="text" type="text"
role="search" role="search"
:title="$t('actions.search')" :title="$t('actions.search')"
@ -174,9 +174,3 @@ export default {
}, },
}; };
</script> </script>
<style>
.input:focus {
@apply border-2 border-red-500;
box-shadow: 0 0 15px rgba(239, 68, 68, var(--tw-border-opacity));
}
</style>

View File

@ -1,46 +1,30 @@
<template> <template>
<div class="modal"> <ModalComponent>
<div> <div class="flex">
<div class="modal-container"> <span class="text-2xl w-max inline-block" v-t="'actions.select_playlist'" />
<div class="flex"> <button class="ml-3" @click="$emit('close')"><font-awesome-icon icon="xmark" /></button>
<span class="text-2xl w-max inline-block" v-t="'actions.select_playlist'" />
<button class="ml-3" @click="$emit('close')"><font-awesome-icon icon="xmark" /></button>
</div>
<select class="select w-full" v-model="selectedPlaylist">
<option
v-for="playlist in playlists"
:value="playlist.id"
:key="playlist.id"
v-text="playlist.name"
/>
</select>
<button
class="btn mt-2"
@click="handleClick(selectedPlaylist)"
ref="addButton"
v-t="'actions.add_to_playlist'"
/>
</div>
</div> </div>
</div> <select class="select w-full mt-3" v-model="selectedPlaylist">
<option v-for="playlist in playlists" :value="playlist.id" :key="playlist.id" v-text="playlist.name" />
</select>
<div class="flex justify-end mt-3">
<button
class="btn"
@click="handleClick(selectedPlaylist)"
ref="addButton"
v-t="'actions.add_to_playlist'"
/>
</div>
</ModalComponent>
</template> </template>
<style scoped>
.modal {
@apply fixed z-50 top-0 left-0 w-full h-full bg-dark-900 bg-opacity-80 transition-opacity table;
}
.modal > div {
@apply table-cell align-middle;
}
.modal-container {
@apply w-min m-auto px-8 bg-dark-700 p-6;
}
</style>
<script> <script>
import ModalComponent from "./ModalComponent.vue";
export default { export default {
components: {
ModalComponent,
},
props: { props: {
videoId: { videoId: {
type: String, type: String,
@ -65,12 +49,10 @@ export default {
}, },
methods: { methods: {
handleKeyDown(event) { handleKeyDown(event) {
if (event.code === "Escape") { if (event.code === "Enter") {
this.$emit("close");
} else if (event.code === "Enter") {
this.handleClick(this.selectedPlaylist); this.handleClick(this.selectedPlaylist);
} else return; event.preventDefault();
event.preventDefault(); }
}, },
handleClick(playlistId) { handleClick(playlistId) {
if (!playlistId) { if (!playlistId) {

View File

@ -53,7 +53,7 @@ export default {
this.fetchJson(this.authApiUrl() + "/user/playlists/rename", null, { this.fetchJson(this.authApiUrl() + "/user/playlists/rename", null, {
method: "POST", method: "POST",
body: JSON.stringify({ body: JSON.stringify({
playlist: id, playlistId: id,
newName: newName, newName: newName,
}), }),
headers: { headers: {

View File

@ -294,7 +294,7 @@
<th v-t="'preferences.instance_locations'" /> <th v-t="'preferences.instance_locations'" />
<th v-t="'preferences.has_cdn'" /> <th v-t="'preferences.has_cdn'" />
<th v-t="'preferences.registered_users'" /> <th v-t="'preferences.registered_users'" />
<th class="<md:(hidden)" v-t="'preferences.version'" /> <th class="lt-md:hidden" v-t="'preferences.version'" />
<th v-t="'preferences.up_to_date'" /> <th v-t="'preferences.up_to_date'" />
<th v-t="'preferences.ssl_score'" /> <th v-t="'preferences.ssl_score'" />
</tr> </tr>
@ -305,7 +305,7 @@
<td v-text="instance.locations" /> <td v-text="instance.locations" />
<td v-text="`${instance.cdn ? '&#9989;' : '&#10060;'}`" /> <td v-text="`${instance.cdn ? '&#9989;' : '&#10060;'}`" />
<td v-text="instance.registered" /> <td v-text="instance.registered" />
<td class="<md:(hidden)" v-text="instance.version" /> <td class="lt-md:hidden" v-text="instance.version" />
<td v-text="`${instance.up_to_date ? '&#9989;' : '&#10060;'}`" /> <td v-text="`${instance.up_to_date ? '&#9989;' : '&#10060;'}`" />
<td> <td>
<a :href="sslScore(instance.api_url)" target="_blank" v-t="'actions.view_ssl_score'" /> <a :href="sslScore(instance.api_url)" target="_blank" v-t="'actions.view_ssl_score'" />
@ -616,6 +616,6 @@ export default {
<style> <style>
.pref { .pref {
@apply flex justify-between items-center my-2 mx-[15vw] <md:(mx-[2vw]); @apply flex justify-between items-center my-2 mx-[15vw] lt-md:mx-[2vw];
} }
</style> </style>

View File

@ -77,7 +77,7 @@ export default {
<style> <style>
.suggestions-container { .suggestions-container {
@apply left-1/2 translate-x-[-50%] transform-gpu max-w-3xl w-full box-border p-y-1.25 z-10 <md:max-w-[calc(100%-0.5rem)] bg-gray-300; @apply left-1/2 translate-x-[-50%] transform-gpu max-w-3xl w-full box-border p-y-1.25 z-10 lt-md:max-w-[calc(100%-0.5rem)] bg-gray-300;
} }
.dark .suggestions-container { .dark .suggestions-container {
@ -85,7 +85,7 @@ export default {
} }
.auto .suggestions-container { .auto .suggestions-container {
@apply dark:bg-dark-400; @apply @dark:bg-dark-400;
} }
.suggestion-selected { .suggestion-selected {
@ -97,7 +97,7 @@ export default {
} }
.auto .suggestion-selected { .auto .suggestion-selected {
@apply dark:bg-dark-100; @apply @dark:bg-dark-100;
} }
.suggestion { .suggestion {

View File

@ -0,0 +1,81 @@
<template>
<ModalComponent>
<div class="flex">
<h2 v-t="'actions.share'" />
<button class="ml-3" @click="$emit('close')"><font-awesome-icon icon="xmark" /></button>
</div>
<div class="flex justify-between mt-4">
<label v-t="'actions.with_timecode'" for="withTimeCode" />
<input id="withTimeCode" type="checkbox" v-model="withTimeCode" />
</div>
<div class="flex justify-between">
<label v-t="'actions.piped_link'" />
<input type="checkbox" v-model="pipedLink" />
</div>
<div class="flex justify-between mt-2">
<label v-t="'actions.time_code'" />
<input class="input w-12" type="text" v-model="timeStamp" />
</div>
<h3 class="mt-4" v-text="generatedLink" />
<div class="flex justify-end mt-4">
<button class="btn" v-t="'actions.follow_link'" @click="followLink()" />
<button class="btn ml-3" v-t="'actions.copy_link'" @click="copyLink()" />
</div>
</ModalComponent>
</template>
<script>
import ModalComponent from "./ModalComponent.vue";
export default {
props: {
videoId: {
type: String,
required: true,
},
currentTime: {
type: Number,
required: true,
},
},
components: {
ModalComponent,
},
data() {
return {
withTimeCode: true,
pipedLink: true,
timeStamp: null,
};
},
mounted() {
this.timeStamp = parseInt(this.currentTime);
},
methods: {
followLink() {
window.open(this.generatedLink, "_blank").focus();
},
async copyLink() {
await this.copyURL(this.generatedLink);
},
async copyURL(mytext) {
try {
await navigator.clipboard.writeText(mytext);
alert(this.$t("info.copied"));
} catch ($e) {
alert(this.$t("info.cannot_copy"));
}
},
},
computed: {
generatedLink() {
var baseUrl = this.pipedLink
? window.location.origin + "/watch?v=" + this.videoId
: "https://youtu.be/" + this.videoId;
var url = new URL(baseUrl);
if (this.withTimeCode && this.timeStamp > 0) url.searchParams.append("t", this.timeStamp);
return url.href;
},
},
};
</script>

View File

@ -21,7 +21,7 @@
<span class="mx-2" v-text="subscription.name" /> <span class="mx-2" v-text="subscription.name" />
</router-link> </router-link>
<button <button
class="btn !w-min" class="btn w-min"
@click="handleButton(subscription)" @click="handleButton(subscription)"
v-t="`actions.${subscription.subscribed ? 'unsubscribe' : 'subscribe'}`" v-t="`actions.${subscription.subscribed ? 'unsubscribe' : 'subscribe'}`"
/> />

View File

@ -31,7 +31,7 @@
v-text="timeFormat(video.duration)" v-text="timeFormat(video.duration)"
/> />
<i18n-t v-else keypath="video.live" class="thumbnail-overlay thumbnail-right !bg-red-600" tag="div"> <i18n-t v-else keypath="video.live" class="thumbnail-overlay thumbnail-right !bg-red-600" tag="div">
<font-awesome-icon class="!w-3" :icon="['fas', 'broadcast-tower']" /> <font-awesome-icon class="w-3" :icon="['fas', 'broadcast-tower']" />
</i18n-t> </i18n-t>
<span v-if="video.watched" class="thumbnail-overlay bottom-5px left-5px" v-t="'video.watched'" /> <span v-if="video.watched" class="thumbnail-overlay bottom-5px left-5px" v-t="'video.watched'" />
</div> </div>

View File

@ -9,7 +9,7 @@ export default {
if (videoId) if (videoId)
this.$router.replace({ this.$router.replace({
path: "/watch", path: "/watch",
query: { v: videoId }, query: { v: videoId, t: this.$route.query.t },
}); });
}, },
}; };

View File

@ -47,13 +47,13 @@
<!-- Likes/dilikes --> <!-- Likes/dilikes -->
<div class="flex children:mr-2"> <div class="flex children:mr-2">
<template v-if="video.likes >= 0"> <template v-if="video.likes >= 0">
<div> <div class="flex">
<font-awesome-icon icon="thumbs-up" /> <div class="i-fa-solid:thumbs-up" />
<strong class="ml-2" v-text="addCommas(video.likes)" /> <strong class="ml-1" v-text="addCommas(video.likes)" />
</div> </div>
<div> <div class="flex">
<font-awesome-icon icon="thumbs-down" /> <div class="i-fa-solid:thumbs-down" />
<strong class="ml-2" v-text="video.dislikes >= 0 ? addCommas(video.dislikes) : '?'" /> <strong class="ml-1" v-text="video.dislikes >= 0 ? addCommas(video.dislikes) : '?'" />
</div> </div>
</template> </template>
<template v-if="video.likes < 0"> <template v-if="video.likes < 0">
@ -88,6 +88,12 @@
/> />
</div> </div>
<PlaylistAddModal v-if="showModal" :video-id="getVideoId()" @close="showModal = !showModal" /> <PlaylistAddModal v-if="showModal" :video-id="getVideoId()" @close="showModal = !showModal" />
<ShareModal
v-if="showShareModal"
:video-id="getVideoId()"
:current-time="currentTime"
@close="showShareModal = !showShareModal"
/>
<div class="flex"> <div class="flex">
<div class="self-center children:mr-1 my-1"> <div class="self-center children:mr-1 my-1">
<!-- RSS Feed button --> <!-- RSS Feed button -->
@ -105,15 +111,10 @@
<font-awesome-icon icon="rss" /> <font-awesome-icon icon="rss" />
</a> </a>
<!-- watch on youtube button --> <!-- watch on youtube button -->
<a :href="`https://youtu.be/${getVideoId()}`" class="btn <lg:hidden"> <button class="btn" @click="showShareModal = !showShareModal">
<i18n-t keypath="player.watch_on" tag="strong"> <i18n-t class="lt-lg:hidden" keypath="actions.share" tag="strong"></i18n-t>
<font-awesome-icon class="mx-1.5" :icon="['fab', 'youtube']" /> <font-awesome-icon class="mx-1.5" icon="fa-share" />
</i18n-t> </button>
</a>
<!-- only visible on small screens -->
<a :href="`https://youtu.be/${getVideoId()}`" class="btn lg:hidden">
<font-awesome-icon class="mx-1.5" :icon="['fab', 'youtube']" />
</a>
<!-- LBRY --> <!-- LBRY -->
<a v-if="video.lbryId" :href="'https://odysee.com/' + video.lbryId" class="btn"> <a v-if="video.lbryId" :href="'https://odysee.com/' + video.lbryId" class="btn">
<i18n-t keypath="player.watch_on" tag="strong">LBRY</i18n-t> <i18n-t keypath="player.watch_on" tag="strong">LBRY</i18n-t>
@ -211,6 +212,7 @@ import ErrorHandler from "./ErrorHandler.vue";
import CommentItem from "./CommentItem.vue"; import CommentItem from "./CommentItem.vue";
import ChaptersBar from "./ChaptersBar.vue"; import ChaptersBar from "./ChaptersBar.vue";
import PlaylistAddModal from "./PlaylistAddModal.vue"; import PlaylistAddModal from "./PlaylistAddModal.vue";
import ShareModal from "./ShareModal.vue";
import PlaylistVideos from "./PlaylistVideos.vue"; import PlaylistVideos from "./PlaylistVideos.vue";
export default { export default {
@ -222,6 +224,7 @@ export default {
CommentItem, CommentItem,
ChaptersBar, ChaptersBar,
PlaylistAddModal, PlaylistAddModal,
ShareModal,
PlaylistVideos, PlaylistVideos,
}, },
data() { data() {
@ -245,6 +248,7 @@ export default {
smallViewQuery: smallViewQuery, smallViewQuery: smallViewQuery,
smallView: smallViewQuery.matches, smallView: smallViewQuery.matches,
showModal: false, showModal: false,
showShareModal: false,
isMobile: true, isMobile: true,
currentTime: 0, currentTime: 0,
}; };
@ -376,7 +380,10 @@ export default {
const parser = new DOMParser(); const parser = new DOMParser();
const xmlDoc = parser.parseFromString(this.video.description, "text/html"); const xmlDoc = parser.parseFromString(this.video.description, "text/html");
xmlDoc.querySelectorAll("a").forEach(elem => (elem.outerHTML = elem.getAttribute("href"))); xmlDoc.querySelectorAll("a").forEach(elem => {
if (!elem.innerText.match(/(?:[\d]{1,2}:)?(?:[\d]{1,2}):(?:[\d]{1,2})/))
elem.outerHTML = elem.getAttribute("href");
});
xmlDoc.querySelectorAll("br").forEach(elem => (elem.outerHTML = "\n")); xmlDoc.querySelectorAll("br").forEach(elem => (elem.outerHTML = "\n"));
this.video.description = this.urlify(xmlDoc.querySelector("body").innerHTML) this.video.description = this.urlify(xmlDoc.querySelector("body").innerHTML)
.replaceAll(/(?:http(?:s)?:\/\/)?(?:www\.)?youtube\.com(\/[/a-zA-Z0-9_?=&-]*)/gm, "$1") .replaceAll(/(?:http(?:s)?:\/\/)?(?:www\.)?youtube\.com(\/[/a-zA-Z0-9_?=&-]*)/gm, "$1")

View File

@ -93,7 +93,11 @@
"clone_playlist": "استنساخ قائمة التشغيل", "clone_playlist": "استنساخ قائمة التشغيل",
"clone_playlist_success": "تم استنساخها بنجاح!", "clone_playlist_success": "تم استنساخها بنجاح!",
"download_as_txt": "تنزيل بتنسيق .txt", "download_as_txt": "تنزيل بتنسيق .txt",
"reset_preferences": "اعادة التعيين للتفضيلات" "reset_preferences": "اعادة التعيين للتفضيلات",
"confirm_reset_preferences": "هل أنت متأكد من أنك تريد إعادة تعيين تفضيلاتك؟",
"backup_preferences": "تفضيلات النسخ الاحتياطي",
"restore_preferences": "استعادة التفضيلات",
"back_to_home": "العودة إلى الصفحة الرئيسية"
}, },
"video": { "video": {
"sponsor_segments": "المقاطع الإعلانية", "sponsor_segments": "المقاطع الإعلانية",
@ -140,5 +144,9 @@
}, },
"information": { "information": {
"preferences_note": "ملاحظة: يتم حفظ التفضيلات في وحدة التخزين المحلية في متصفحك. سيؤدي حذف بيانات المتصفح إلى إعادة تعيينها." "preferences_note": "ملاحظة: يتم حفظ التفضيلات في وحدة التخزين المحلية في متصفحك. سيؤدي حذف بيانات المتصفح إلى إعادة تعيينها."
},
"info": {
"preferences_note": "ملاحظة: يتم حفظ التفضيلات في وحدة التخزين المحلية في متصفحك. سيؤدي حذف بيانات المتصفح إلى إعادة تعيينها.",
"page_not_found": "لم يتم العثور على الصفحة"
} }
} }

View File

@ -7,7 +7,10 @@
"preferences": "Seçimlər", "preferences": "Seçimlər",
"history": "Tarixçə", "history": "Tarixçə",
"subscriptions": "Abunəliklər", "subscriptions": "Abunəliklər",
"playlists": "Pleylistlər" "playlists": "Pleylistlər",
"account": "Hesab",
"instance": "Server",
"player": "Oynadıcı"
}, },
"player": { "player": {
"watch_on": "{0} saytında baxın" "watch_on": "{0} saytında baxın"
@ -67,14 +70,14 @@
"delete_playlist": "Pleylisti Silin", "delete_playlist": "Pleylisti Silin",
"select_playlist": "Pleylist Seçin", "select_playlist": "Pleylist Seçin",
"delete_playlist_confirm": "Bu pleylist silinsin?", "delete_playlist_confirm": "Bu pleylist silinsin?",
"please_select_playlist": "Lütfən, Pleylist Seçin", "please_select_playlist": "Lütfən, pleylist seçin",
"country_selection": "Ölkə Seçimi", "country_selection": "Ölkə Seçimi",
"default_homepage": "Defolt Əsas Səhifə", "default_homepage": "Defolt Əsas Səhifə",
"show_comments": "Şərhləri Göstərin", "show_comments": "Şərhləri Göstərin",
"instance_selection": "Nümunə Seçimi", "instance_selection": "Server Seçimi",
"minimize_description_default": "Açıqlamanı Defolt Olaraq Kiçildin", "minimize_description_default": "Açıqlamanı Defolt Olaraq Kiçildin",
"language_selection": "Dil Seçimi", "language_selection": "Dil Seçimi",
"instances_list": "Nümunələr Siyahısı", "instances_list": "Serverlər Siyahısı",
"show_more": "Daha Çox Göstər", "show_more": "Daha Çox Göstər",
"no": "Xeyr", "no": "Xeyr",
"store_watch_history": "Baxış Tarixçəsini Saxlayın", "store_watch_history": "Baxış Tarixçəsini Saxlayın",
@ -83,10 +86,23 @@
"show_markers": "Oynadıcıda Markerləri Göstərin", "show_markers": "Oynadıcıda Markerləri Göstərin",
"delete_account": "Hesabı Silin", "delete_account": "Hesabı Silin",
"logout": "Bu cihazdan çıxın", "logout": "Bu cihazdan çıxın",
"minimize_recommendations_default": "Defolt olaraq Tövsiyələri minimuma endir" "minimize_recommendations_default": "Defolt olaraq Tövsiyələri minimuma endir",
"download_as_txt": ".txt kimi endirin",
"reset_preferences": "Seçimləri sıfırlayın",
"confirm_reset_preferences": "Seçimləri sıfırlamaq istədiyinizə əminsiniz?",
"backup_preferences": "Yedəkləmə seçimləri",
"restore_preferences": "Seçimləri bərpa edin",
"invalidate_session": "Bütün cihazlardan çıxın",
"different_auth_instance": "Doğrulama üçün fərqli bir serverdən istifadə edin",
"instance_auth_selection": "Autentifikasiya Server Seçimi",
"clone_playlist": "Pleylist Klonlanması",
"clone_playlist_success": "Uğurla klonlandı!"
}, },
"comment": { "comment": {
"pinned_by": "Tərəfindən Sabitləndi" "pinned_by": "Tərəfindən Sabitləndi",
"disabled": "Şərhlər yükləyici tərəfindən deaktiv edilib.",
"loading": "Şərhlər yüklənir...",
"user_disabled": "Şərhlər tənzimləmələrdə deaktiv edilib."
}, },
"preferences": { "preferences": {
"instance_name": "Nümunə Adı", "instance_name": "Nümunə Adı",
@ -94,7 +110,7 @@
"has_cdn": "CDN varmı?", "has_cdn": "CDN varmı?",
"registered_users": "Qeydiyyatdan Keçmiş İstifadəçilər", "registered_users": "Qeydiyyatdan Keçmiş İstifadəçilər",
"version": "Versiya", "version": "Versiya",
"up_to_date": "Yenilənib?", "up_to_date": "Güncəllənib?",
"ssl_score": "SSL Nəticəsi" "ssl_score": "SSL Nəticəsi"
}, },
"login": { "login": {
@ -104,12 +120,12 @@
"video": { "video": {
"videos": "Videolar", "videos": "Videolar",
"views": "{views} baxış", "views": "{views} baxış",
"watched": "Baxılmış", "watched": "Baxılıb",
"sponsor_segments": "Sponsorlar Seqmentləri", "sponsor_segments": "Sponsorlar Seqmentləri",
"ratings_disabled": "Reytinqlər Deaktivdir", "ratings_disabled": "Reytinqlər Deaktivdir",
"chapters": "Bölümlər", "chapters": "Bölümlər",
"live": "{0} Canlı", "live": "{0} Canlı",
"shorts": "Qısa videolar" "shorts": "Qısa"
}, },
"search": { "search": {
"did_you_mean": "Bunu nəzərdə tutursunuz: {0}?", "did_you_mean": "Bunu nəzərdə tutursunuz: {0}?",
@ -121,5 +137,11 @@
"music_videos": "YT Music: Videolar", "music_videos": "YT Music: Videolar",
"music_albums": "YT Music: Albomlar", "music_albums": "YT Music: Albomlar",
"music_playlists": "YT Music: Pleylistlər" "music_playlists": "YT Music: Pleylistlər"
},
"subscriptions": {
"subscribed_channels_count": "Abunə oldu: {0}"
},
"information": {
"preferences_note": "Qeyd: seçimlər brauzerinizin yerli yaddaşında saxlanılır. Brauzer məlumatlarınızın silinməsi onları sıfırlayacaq."
} }
} }

View File

@ -90,7 +90,10 @@
"clone_playlist": "Clonar Llista de Reproducció", "clone_playlist": "Clonar Llista de Reproducció",
"clone_playlist_success": "Clonada correctament!", "clone_playlist_success": "Clonada correctament!",
"download_as_txt": "Descarrega com a .txt", "download_as_txt": "Descarrega com a .txt",
"reset_preferences": "Restablir preferències" "reset_preferences": "Restablir preferències",
"restore_preferences": "Restaura les preferències",
"backup_preferences": "Preferències de la còpia de seguretat",
"confirm_reset_preferences": "Esteu segur que voleu restablir les vostres preferències?"
}, },
"comment": { "comment": {
"pinned_by": "Fixat per", "pinned_by": "Fixat per",

View File

@ -37,7 +37,7 @@
"default_homepage": "Výchozí domovská stránka", "default_homepage": "Výchozí domovská stránka",
"show_comments": "Zobrazit komentáře", "show_comments": "Zobrazit komentáře",
"minimize_description_default": "Automaticky minimalizovat popis", "minimize_description_default": "Automaticky minimalizovat popis",
"store_watch_history": "Uložit historii sledování", "store_watch_history": "Ukládat historii sledování",
"language_selection": "Výběr jazyka", "language_selection": "Výběr jazyka",
"instances_list": "Seznam instancí", "instances_list": "Seznam instancí",
"enabled_codecs": "Povolené kodeky (několik)", "enabled_codecs": "Povolené kodeky (několik)",
@ -90,7 +90,11 @@
"clone_playlist": "Duplikovat playlist", "clone_playlist": "Duplikovat playlist",
"clone_playlist_success": "Úspěšně duplikováno!", "clone_playlist_success": "Úspěšně duplikováno!",
"download_as_txt": "Stáhnout jako .txt", "download_as_txt": "Stáhnout jako .txt",
"reset_preferences": "Resetovat předvolby" "reset_preferences": "Resetovat předvolby",
"restore_preferences": "Obnovit předvolby",
"backup_preferences": "Zálohovat předvolby",
"confirm_reset_preferences": "Opravdu chcete resetovat své předvolby?",
"back_to_home": "Zpátky domů"
}, },
"player": { "player": {
"watch_on": "Sledovat na {0}" "watch_on": "Sledovat na {0}"
@ -107,7 +111,7 @@
"has_cdn": "Používá CDN?", "has_cdn": "Používá CDN?",
"ssl_score": "Stav SSL", "ssl_score": "Stav SSL",
"registered_users": "Registrovaní uživatelé", "registered_users": "Registrovaní uživatelé",
"up_to_date": "Aktualizovaný?", "up_to_date": "Aktuální?",
"version": "Verze" "version": "Verze"
}, },
"login": { "login": {
@ -140,5 +144,9 @@
}, },
"information": { "information": {
"preferences_note": "Poznámka: předvolby jsou uloženy v místním úložišti vašeho prohlížeče. Odstranění dat vašeho prohlížeče je resetuje." "preferences_note": "Poznámka: předvolby jsou uloženy v místním úložišti vašeho prohlížeče. Odstranění dat vašeho prohlížeče je resetuje."
},
"info": {
"preferences_note": "Poznámka: předvolby se ukládají do místního úložiště prohlížeče. Vymazáním dat prohlížeče budou obnoveny.",
"page_not_found": "Stránka nenalezena"
} }
} }

View File

@ -99,7 +99,13 @@
"restore_preferences": "Restore preferences", "restore_preferences": "Restore preferences",
"back_to_home": "Back to home", "back_to_home": "Back to home",
"rename_playlist": "Rename playlist", "rename_playlist": "Rename playlist",
"new_playlist_name": "New playlist name" "new_playlist_name": "New playlist name",
"share": "Share",
"with_timecode": "Share with time code",
"piped_link": "Piped link",
"follow_link": "Follow link",
"copy_link": "Copy link",
"time_code": "Time code (in seconds)"
}, },
"comment": { "comment": {
"pinned_by": "Pinned by", "pinned_by": "Pinned by",
@ -146,6 +152,8 @@
}, },
"info": { "info": {
"preferences_note": "Note: preferences are saved in the local storage of your browser. Deleting your browser data will reset them.", "preferences_note": "Note: preferences are saved in the local storage of your browser. Deleting your browser data will reset them.",
"page_not_found": "Page not found" "page_not_found": "Page not found",
"copied": "Copied!",
"cannot_copy": "Can't copy!"
} }
} }

View File

@ -7,7 +7,10 @@
"preferences": "Préférences", "preferences": "Préférences",
"history": "Historique", "history": "Historique",
"subscriptions": "Abonnements", "subscriptions": "Abonnements",
"playlists": "Listes de lecture" "playlists": "Listes de lecture",
"account": "Compte",
"instance": "Instance",
"player": "Lecteur"
}, },
"actions": { "actions": {
"subscribe": "S'abonner - {count}", "subscribe": "S'abonner - {count}",
@ -86,7 +89,11 @@
"instance_auth_selection": "Sélection de l'instance d'authentification", "instance_auth_selection": "Sélection de l'instance d'authentification",
"clone_playlist": "Cloner la liste de lecture", "clone_playlist": "Cloner la liste de lecture",
"clone_playlist_success": "Clonage réussi !", "clone_playlist_success": "Clonage réussi !",
"download_as_txt": "Télécharger en tant que" "download_as_txt": "Télécharger en tant que",
"reset_preferences": "Réinitialiser les préférences",
"confirm_reset_preferences": "Êtes-vous sûre de vouloir réinitialiser les préférences ?",
"restore_preferences": "Restaurer les préférences",
"backup_preferences": "Sauvegarde des préférences"
}, },
"player": { "player": {
"watch_on": "Regarder sur {0}" "watch_on": "Regarder sur {0}"
@ -133,5 +140,8 @@
}, },
"subscriptions": { "subscriptions": {
"subscribed_channels_count": "Abonné à : {0}" "subscribed_channels_count": "Abonné à : {0}"
},
"information": {
"preferences_note": "Note : les préférences sont sauvegardées dans le stockage local de votre navigateur. Supprimer les données de votre navigateur les réinitialiserons."
} }
} }

View File

@ -7,7 +7,8 @@
"history": "Előzmények", "history": "Előzmények",
"subscriptions": "Feliratkozások", "subscriptions": "Feliratkozások",
"playlists": "Lejátszási listák", "playlists": "Lejátszási listák",
"trending": "Felkapott" "trending": "Felkapott",
"account": "Fiók"
}, },
"actions": { "actions": {
"subscribe": "Feliratkozás - {count}", "subscribe": "Feliratkozás - {count}",

View File

@ -93,7 +93,10 @@
"clone_playlist_success": "Berhasil disalin!", "clone_playlist_success": "Berhasil disalin!",
"clone_playlist": "Salin Daftar Putar", "clone_playlist": "Salin Daftar Putar",
"download_as_txt": "Unduh sebagai .txt", "download_as_txt": "Unduh sebagai .txt",
"reset_preferences": "Atur ulang preferensi" "reset_preferences": "Atur ulang preferensi",
"restore_preferences": "Pulihkan preferensi",
"confirm_reset_preferences": "Apakah Anda yakin ingin mengatur ulang preferensi Anda?",
"backup_preferences": "Cadangkan preferensi"
}, },
"comment": { "comment": {
"pinned_by": "Dipasangi pin oleh", "pinned_by": "Dipasangi pin oleh",

View File

@ -76,7 +76,12 @@
"instance_auth_selection": "Selezione dell'istanza di autenticazione", "instance_auth_selection": "Selezione dell'istanza di autenticazione",
"clone_playlist_success": "Clonato con successo!", "clone_playlist_success": "Clonato con successo!",
"clone_playlist": "Clona la playlist", "clone_playlist": "Clona la playlist",
"download_as_txt": "Scarica come .txt" "download_as_txt": "Scarica come .txt",
"confirm_reset_preferences": "Confermi di voler reimpostare le preferenze?",
"restore_preferences": "Ripristina le preferenze",
"reset_preferences": "Reimposta le preferenze",
"backup_preferences": "Salva un backup delle preferenze",
"back_to_home": "Torna alla pagina iniziale"
}, },
"player": { "player": {
"watch_on": "Guarda su {0}" "watch_on": "Guarda su {0}"
@ -89,7 +94,10 @@
"login": "Accedi", "login": "Accedi",
"trending": "Di tendenza", "trending": "Di tendenza",
"subscriptions": "Iscrizioni", "subscriptions": "Iscrizioni",
"playlists": "Playlist" "playlists": "Playlist",
"account": "Account",
"instance": "Istanza",
"player": "Riproduttore"
}, },
"video": { "video": {
"sponsor_segments": "Segmenti sponsor", "sponsor_segments": "Segmenti sponsor",
@ -133,5 +141,12 @@
}, },
"subscriptions": { "subscriptions": {
"subscribed_channels_count": "Abbonato a: {0}" "subscribed_channels_count": "Abbonato a: {0}"
},
"information": {
"preferences_note": "Nota: le preferenze sono salvate nella memoria locale del tuo browser. Se cancelli i dati del browser, le preferenze saranno ripristinate."
},
"info": {
"page_not_found": "Pagina non trovata",
"preferences_note": "Nota: le preferenze sono salvate nella memoria locale del tuo browser. L'eliminazione dei dati del tuo browser le ripristinerà."
} }
} }

View File

@ -1,34 +1,34 @@
{ {
"actions": { "actions": {
"instances_list": "Liste over instanser", "instances_list": "Liste over instanser",
"minimize_description_default": "Minimer beskrivelse som forvalg", "minimize_description_default": "Minimer beskrivelse som standard",
"country_selection": "Land", "country_selection": "Land",
"buffering_goal": "Mellomlagringsmål (i sekunder)", "buffering_goal": "Mellomlagringsmål (i sekunder)",
"autoplay_video": "Spill video automatisk", "autoplay_video": "Spill video automatisk",
"skip_non_music": "Hopp over musikk:Del uten musikk", "skip_non_music": "Hopp over musikk: del uten musikk",
"auto": "Auto", "auto": "Auto",
"skip_self_promo": "Hopp over ubetalt/selvpromotering", "skip_self_promo": "Hopp over ubetalt/selvpromotering",
"skip_interaction": "Hopp over interaksjonspåminnelse (abonnering)", "skip_interaction": "Hopp over interaksjonspåminnelse (abonnering)",
"skip_preview": "Hopp over forhåndsvisning/reintroduksjon", "skip_preview": "Hopp over forhåndsvisning/reintroduksjon",
"skip_outro": "Skru av rulletekst/sluttpresentasjon", "skip_outro": "Hopp over rulletekst/utro",
"skip_intro": "Hopp over forvideo/introanimasjon", "skip_intro": "Hopp over forvideo/introanimasjon",
"enable_sponsorblock": "Skru på sponsorblokkering", "enable_sponsorblock": "Skru på sponsorblokkering",
"language_selection": "Språk", "language_selection": "Språk",
"store_watch_history": "Lagre visningshistorikk", "store_watch_history": "Lagre visningshistorikk",
"show_comments": "Vis kommentarer", "show_comments": "Vis kommentarer",
"default_homepage": "Forvalgt hjemmeside", "default_homepage": "Standard hjemmeside",
"default_quality": "Forvalgt kvalitet", "default_quality": "Standard kvalitet",
"audio_only": "Kun lyd", "audio_only": "Kun lyd",
"light": "Lys", "light": "Lys",
"dark": "Mørk", "dark": "Mørk",
"theme": "Drakt", "theme": "Tema",
"skip_sponsors": "Hopp over sponsorer", "skip_sponsors": "Hopp over sponsorer",
"uses_api_from": "Bruker API-et fra ", "uses_api_from": "Bruker API-et fra ",
"back": "Tilbake", "back": "Tilbake",
"channel_name_desc": "Kanalnavn (Å-A)", "channel_name_desc": "Kanalnavn (Å-A)",
"channel_name_asc": "Kanalnavn (A-Å)", "channel_name_asc": "Kanalnavn (A-Å)",
"least_recent": "Eldst", "least_recent": "Eldst",
"most_recent": "Nyligst", "most_recent": "Nyest",
"sort_by": "Sorter etter:", "sort_by": "Sorter etter:",
"view_subscriptions": "Vis abonnementer", "view_subscriptions": "Vis abonnementer",
"unsubscribe": "Opphev abonnement - {count}", "unsubscribe": "Opphev abonnement - {count}",
@ -37,7 +37,7 @@
"disable_lbry": "Skru av LBRY-strømming", "disable_lbry": "Skru av LBRY-strømming",
"enabled_codecs": "Aktiverte forskjellige kodek", "enabled_codecs": "Aktiverte forskjellige kodek",
"show_description": "Vis beskrivelse", "show_description": "Vis beskrivelse",
"minimize_recommendations": "Minimere anbefalinger", "minimize_recommendations": "Minimer anbefalinger",
"show_recommendations": "Vis anbefalinger", "show_recommendations": "Vis anbefalinger",
"donations": "Donasjoner", "donations": "Donasjoner",
"auto_play_next_video": "Autospill neste video", "auto_play_next_video": "Autospill neste video",
@ -49,7 +49,7 @@
"show_more": "Vis mer", "show_more": "Vis mer",
"instance_selection": "Valg av instans", "instance_selection": "Valg av instans",
"search": "Søk", "search": "Søk",
"filter": "Filter", "filter": "Filtrer",
"loading": "Laster inn …", "loading": "Laster inn …",
"view_ssl_score": "Vis SSL-poengsum", "view_ssl_score": "Vis SSL-poengsum",
"minimize_description": "Minimer beskrivelse", "minimize_description": "Minimer beskrivelse",
@ -60,10 +60,10 @@
"skip_highlight": "Hopp over hovedmoment", "skip_highlight": "Hopp over hovedmoment",
"load_more_replies": "Last inn flere svar", "load_more_replies": "Last inn flere svar",
"create_playlist": "Opprett spilleliste", "create_playlist": "Opprett spilleliste",
"delete_playlist_confirm": "Slett denne spillelisten?", "delete_playlist_confirm": "Er du sikker på at du vil slette spillelisten?",
"delete_playlist": "Slett spilleliste", "delete_playlist": "Slett spilleliste",
"select_playlist": "Velg en spilleliste", "select_playlist": "Velg spilleliste",
"please_select_playlist": "Velg en spilleliste", "please_select_playlist": "Vennligst velg en spilleliste",
"delete_playlist_video_confirm": "Fjern video fra spilleliste?", "delete_playlist_video_confirm": "Fjern video fra spilleliste?",
"show_markers": "Vis markører i avspiller", "show_markers": "Vis markører i avspiller",
"add_to_playlist": "Legg til i spilleliste", "add_to_playlist": "Legg til i spilleliste",
@ -78,7 +78,7 @@
"clone_playlist": "Klon spillelisten", "clone_playlist": "Klon spillelisten",
"clone_playlist_success": "Klonet", "clone_playlist_success": "Klonet",
"reset_preferences": "Tilbakestill innstillinger", "reset_preferences": "Tilbakestill innstillinger",
"backup_preferences": "Sikkerhetskopieringsinnstillinger", "backup_preferences": "Innstillinger for sikkerhetskopiering",
"confirm_reset_preferences": "Tilbakestill alle innstillingene?", "confirm_reset_preferences": "Tilbakestill alle innstillingene?",
"restore_preferences": "Gjenopprett innstillinger" "restore_preferences": "Gjenopprett innstillinger"
}, },
@ -87,7 +87,7 @@
}, },
"titles": { "titles": {
"feed": "Strøm", "feed": "Strøm",
"history": "HIstorikk", "history": "Historikk",
"preferences": "Innstillinger", "preferences": "Innstillinger",
"register": "Registrering", "register": "Registrering",
"login": "Logg inn", "login": "Logg inn",
@ -103,7 +103,7 @@
"watched": "Sett", "watched": "Sett",
"views": "{views} visninger", "views": "{views} visninger",
"videos": "Videoer", "videos": "Videoer",
"ratings_disabled": "Vurderinger avskrudd", "ratings_disabled": "Vurdering deaktivert",
"chapters": "Kapitler", "chapters": "Kapitler",
"live": "{0} direkte", "live": "{0} direkte",
"shorts": "Korte" "shorts": "Korte"

View File

@ -7,7 +7,10 @@
"register": "Registar", "register": "Registar",
"history": "Histórico", "history": "Histórico",
"feed": "Feed", "feed": "Feed",
"playlists": "Listas de reprodução" "playlists": "Listas de reprodução",
"account": "Conta",
"instance": "Instância",
"player": "Reprodutor"
}, },
"actions": { "actions": {
"sort_by": "Ordenar por:", "sort_by": "Ordenar por:",
@ -85,7 +88,11 @@
"minimize_recommendations_default": "Minimizar recomendações por definição", "minimize_recommendations_default": "Minimizar recomendações por definição",
"invalidate_session": "Terminar sessão em todos os dispositivos", "invalidate_session": "Terminar sessão em todos os dispositivos",
"different_auth_instance": "Use uma instância diferente para autenticação", "different_auth_instance": "Use uma instância diferente para autenticação",
"instance_auth_selection": "Seleção de instância de autenticação" "instance_auth_selection": "Seleção de instância de autenticação",
"confirm_reset_preferences": "Tem a certeza de que deseja restaurar as preferências originais?",
"download_as_txt": "Descarregar como txt",
"reset_preferences": "Repor definições originais",
"restore_preferences": "Restaurar preferências"
}, },
"preferences": { "preferences": {
"instance_name": "Nome da instância", "instance_name": "Nome da instância",

View File

@ -7,7 +7,10 @@
"subscriptions": "Prenumerationer", "subscriptions": "Prenumerationer",
"feed": "Flöde", "feed": "Flöde",
"history": "Historik", "history": "Historik",
"playlists": "Spellistor" "playlists": "Spellistor",
"account": "Konto",
"instance": "Instans",
"player": "Spelare"
}, },
"actions": { "actions": {
"subscribe": "Prenumerera - {count}", "subscribe": "Prenumerera - {count}",
@ -86,7 +89,11 @@
"invalidate_session": "Logga ut alla enheter", "invalidate_session": "Logga ut alla enheter",
"different_auth_instance": "Använd en annan instans för autentisering", "different_auth_instance": "Använd en annan instans för autentisering",
"instance_auth_selection": "Val av autentiseringsinstans", "instance_auth_selection": "Val av autentiseringsinstans",
"download_as_txt": "Ladda ner som .txt" "download_as_txt": "Ladda ner som .txt",
"reset_preferences": "Återställ inställningar",
"confirm_reset_preferences": "Är du säker på att du vill återställa dina inställningar?",
"backup_preferences": "Inställningar för säkerhetskopiering",
"restore_preferences": "Återställa inställningar"
}, },
"player": { "player": {
"watch_on": "Titta på {0}" "watch_on": "Titta på {0}"
@ -133,5 +140,8 @@
}, },
"subscriptions": { "subscriptions": {
"subscribed_channels_count": "Prenumererar på: {0}" "subscribed_channels_count": "Prenumererar på: {0}"
},
"information": {
"preferences_note": "Observera: inställningar sparas i webbläsarens lokala lagring. Om du raderar dina webbläsardata återställs de."
} }
} }

View File

@ -80,7 +80,8 @@
"reset_preferences": "Tercihleri sıfırla", "reset_preferences": "Tercihleri sıfırla",
"confirm_reset_preferences": "Tercihlerinizi sıfırlamak istediğinize emin misiniz?", "confirm_reset_preferences": "Tercihlerinizi sıfırlamak istediğinize emin misiniz?",
"backup_preferences": "Tercihleri yedekle", "backup_preferences": "Tercihleri yedekle",
"restore_preferences": "Tercihleri geri yükle" "restore_preferences": "Tercihleri geri yükle",
"back_to_home": "Ana sayfaya dön"
}, },
"player": { "player": {
"watch_on": "{0} üzerinde izle" "watch_on": "{0} üzerinde izle"
@ -143,5 +144,9 @@
}, },
"information": { "information": {
"preferences_note": "Not: Tercihler tarayıcınızın yerel depolama alanına kaydedilir. Tarayıcı verilerinizi silmek onları sıfırlayacaktır." "preferences_note": "Not: Tercihler tarayıcınızın yerel depolama alanına kaydedilir. Tarayıcı verilerinizi silmek onları sıfırlayacaktır."
},
"info": {
"preferences_note": "Not: Tercihler tarayıcınızın yerel depolama alanına kaydedilir. Tarayıcı verilerinizi silmek onları sıfırlayacaktır.",
"page_not_found": "Sayfa bulunamadı"
} }
} }

View File

@ -55,11 +55,12 @@
"remove_from_playlist": "從播放清單中移除", "remove_from_playlist": "從播放清單中移除",
"create_playlist": "建立播放清單", "create_playlist": "建立播放清單",
"delete_playlist": "刪除播放清單", "delete_playlist": "刪除播放清單",
"delete_playlist_confirm": "確定要刪除此播放清單嗎?", "delete_playlist_confirm": "要刪除這份播放清單嗎?",
"please_select_playlist": "請選擇播放清單", "please_select_playlist": "請選擇播放清單",
"select_playlist": "選擇播放清單", "select_playlist": "選擇播放清單",
"add_to_playlist": "加到播放清單", "add_to_playlist": "加到播放清單",
"delete_playlist_video_confirm": "確定要將此影片從此播放清單中移除嗎?" "delete_playlist_video_confirm": "要從播放清單中移除影片嗎?",
"delete_account": "刪除帳戶"
}, },
"titles": { "titles": {
"history": "歷史記錄", "history": "歷史記錄",
@ -69,7 +70,8 @@
"register": "註冊", "register": "註冊",
"login": "登入", "login": "登入",
"subscriptions": "訂閱內容", "subscriptions": "訂閱內容",
"playlists": "播放清單" "playlists": "播放清單",
"account": "帳戶"
}, },
"preferences": { "preferences": {
"registered_users": "已註冊的使用者", "registered_users": "已註冊的使用者",
@ -99,6 +101,8 @@
"music_albums": "YT Music專輯" "music_albums": "YT Music專輯"
}, },
"comment": { "comment": {
"pinned_by": "置頂者:" "pinned_by": "置頂者:",
"disabled": "上傳者停用了留言功能。",
"loading": "留言載入中……"
} }
} }

View File

@ -1,8 +1,6 @@
import { createApp } from "vue"; import { createApp } from "vue";
import { library } from "@fortawesome/fontawesome-svg-core"; import { library } from "@fortawesome/fontawesome-svg-core";
import { import {
faThumbsUp,
faThumbsDown,
faEye, faEye,
faThumbtack, faThumbtack,
faCheck, faCheck,
@ -18,12 +16,11 @@ import {
faCircleMinus, faCircleMinus,
faXmark, faXmark,
faClone, faClone,
faShare,
} from "@fortawesome/free-solid-svg-icons"; } from "@fortawesome/free-solid-svg-icons";
import { faGithub, faBitcoin, faYoutube } from "@fortawesome/free-brands-svg-icons"; import { faGithub, faBitcoin } from "@fortawesome/free-brands-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
library.add( library.add(
faThumbsUp,
faThumbsDown,
faEye, faEye,
faGithub, faGithub,
faBitcoin, faBitcoin,
@ -31,7 +28,6 @@ library.add(
faCheck, faCheck,
faHeart, faHeart,
faHeadphones, faHeadphones,
faYoutube,
faRss, faRss,
faChevronLeft, faChevronLeft,
faLevelDownAlt, faLevelDownAlt,
@ -42,6 +38,7 @@ library.add(
faCircleMinus, faCircleMinus,
faXmark, faXmark,
faClone, faClone,
faShare,
); );
import router from "@/router/router.js"; import router from "@/router/router.js";
@ -57,7 +54,8 @@ TimeAgo.addDefaultLocale(en);
import { createI18n } from "vue-i18n"; import { createI18n } from "vue-i18n";
import enLocale from "@/locales/en.json"; import enLocale from "@/locales/en.json";
import "windi.css"; import "@unocss/reset/tailwind.css";
import "uno.css";
const timeAgo = new TimeAgo("en-US"); const timeAgo = new TimeAgo("en-US");
@ -179,6 +177,7 @@ const mixin = {
const emailRegex = /([\w-\\.]+@(?:[\w-]+\.)+[\w-]{2,4})/g; const emailRegex = /([\w-\\.]+@(?:[\w-]+\.)+[\w-]{2,4})/g;
return string return string
.replace(urlRegex, url => { .replace(urlRegex, url => {
if (url.endsWith("</a>")) return url;
return `<a href="${url}" target="_blank">${url}</a>`; return `<a href="${url}" target="_blank">${url}</a>`;
}) })
.replace(emailRegex, email => { .replace(emailRegex, email => {

34
uno.config.js Normal file
View File

@ -0,0 +1,34 @@
import { defineConfig } from "unocss";
import transformerDirective from "@unocss/transformer-directives";
import transformerVariantGroup from "@unocss/transformer-variant-group";
import presetUno from "@unocss/preset-uno";
import presetIcons from "@unocss/preset-icons";
import presetWebFonts from "@unocss/preset-web-fonts";
export default defineConfig({
transformers: [transformerDirective(), transformerVariantGroup()],
presets: [
presetUno(),
presetIcons(),
presetWebFonts({
provider: "none",
fonts: {
sans: [
"-apple-system",
"BlinkMacSystemFont",
"Segoe UI",
"Roboto",
"Helvetica Neue",
"Arial",
"Noto Sans",
"sans-serif",
"Apple Color Emoji",
"Segoe UI Emoji",
"Segoe UI Symbol",
"Noto Color Emoji",
],
},
}),
],
});

View File

@ -1,6 +1,6 @@
import { defineConfig } from "vite"; import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue"; import vue from "@vitejs/plugin-vue";
import WindiCSS from "vite-plugin-windicss"; import Unocss from "unocss/vite";
import legacy from "@vitejs/plugin-legacy"; import legacy from "@vitejs/plugin-legacy";
import vueI18n from "@intlify/vite-plugin-vue-i18n"; import vueI18n from "@intlify/vite-plugin-vue-i18n";
import { VitePWA } from "vite-plugin-pwa"; import { VitePWA } from "vite-plugin-pwa";
@ -11,7 +11,7 @@ import eslintPlugin from "vite-plugin-eslint";
export default defineConfig({ export default defineConfig({
plugins: [ plugins: [
vue(), vue(),
WindiCSS(), Unocss(),
vueI18n({ vueI18n({
include: path.resolve(__dirname, "./src/locales/**"), include: path.resolve(__dirname, "./src/locales/**"),
}), }),

View File

@ -1,23 +0,0 @@
module.exports = {
darkMode: "media",
theme: {
extend: {
fontFamily: {
sans: [
"-apple-system",
"BlinkMacSystemFont",
"Segoe UI",
"Roboto",
"Helvetica Neue",
"Arial",
"Noto Sans",
"sans-serif",
"Apple Color Emoji",
"Segoe UI Emoji",
"Segoe UI Symbol",
"Noto Color Emoji",
],
},
},
},
};

802
yarn.lock

File diff suppressed because it is too large Load Diff