mirror of
				https://github.com/TeamPiped/Piped.git
				synced 2024-08-14 23:57:27 +00:00 
			
		
		
		
	Merge remote-tracking branch 'origin/master' into toast
This commit is contained in:
		
						commit
						defefed9ed
					
				
					 37 changed files with 1176 additions and 729 deletions
				
			
		| 
						 | 
					@ -143,6 +143,7 @@ Contributions in any other form are also welcomed.
 | 
				
			||||||
-   [Hyperpipe](https://codeberg.org/Hyperpipe/Hyperpipe) - an alternative privacy respecting frontend for YouTube Music.
 | 
					-   [Hyperpipe](https://codeberg.org/Hyperpipe/Hyperpipe) - an alternative privacy respecting frontend for YouTube Music.
 | 
				
			||||||
-   [Musicale](https://github.com/Bellisario/musicale) - an alternative to YouTube Music, with style.
 | 
					-   [Musicale](https://github.com/Bellisario/musicale) - an alternative to YouTube Music, with style.
 | 
				
			||||||
-   [ytify](https://github.com/n-ce/ytify) - a complementary minimal audio streaming frontend for YouTube.
 | 
					-   [ytify](https://github.com/n-ce/ytify) - a complementary minimal audio streaming frontend for YouTube.
 | 
				
			||||||
 | 
					-   [PsTube](https://github.com/prateekmedia/pstube) - Watch and download videos without ads
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## YourKit
 | 
					## YourKit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@ server {
 | 
				
			||||||
    listen 80;
 | 
					    listen 80;
 | 
				
			||||||
    listen [::]:80;
 | 
					    listen [::]:80;
 | 
				
			||||||
    server_name localhost;
 | 
					    server_name localhost;
 | 
				
			||||||
 | 
					    error_log off;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    location / {
 | 
					    location / {
 | 
				
			||||||
        root /usr/share/nginx/html;
 | 
					        root /usr/share/nginx/html;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,6 +7,7 @@
 | 
				
			||||||
        <link rel="icon" href="/favicon.ico" />
 | 
					        <link rel="icon" href="/favicon.ico" />
 | 
				
			||||||
        <link title="Piped" type="application/opensearchdescription+xml" rel="search" href="/opensearch.xml" />
 | 
					        <link title="Piped" type="application/opensearchdescription+xml" rel="search" href="/opensearch.xml" />
 | 
				
			||||||
        <title>Piped</title>
 | 
					        <title>Piped</title>
 | 
				
			||||||
 | 
					        <meta name="theme-color" content="#0f0f0f">
 | 
				
			||||||
        <meta property="og:title" content="Piped" />
 | 
					        <meta property="og:title" content="Piped" />
 | 
				
			||||||
        <meta property="og:type" content="website" />
 | 
					        <meta property="og:type" content="website" />
 | 
				
			||||||
        <meta property="og:image" content="/img/icons/favicon-32x32.png" />
 | 
					        <meta property="og:image" content="/img/icons/favicon-32x32.png" />
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										26
									
								
								package.json
									
										
									
									
									
								
							
							
						
						
									
										26
									
								
								package.json
									
										
									
									
									
								
							| 
						 | 
					@ -14,11 +14,11 @@
 | 
				
			||||||
        "@fortawesome/free-solid-svg-icons": "6.3.0",
 | 
					        "@fortawesome/free-solid-svg-icons": "6.3.0",
 | 
				
			||||||
        "@fortawesome/vue-fontawesome": "3.0.3",
 | 
					        "@fortawesome/vue-fontawesome": "3.0.3",
 | 
				
			||||||
        "buffer": "6.0.3",
 | 
					        "buffer": "6.0.3",
 | 
				
			||||||
        "dompurify": "3.0.0",
 | 
					        "dompurify": "3.0.1",
 | 
				
			||||||
        "hotkeys-js": "3.10.1",
 | 
					        "hotkeys-js": "3.10.1",
 | 
				
			||||||
        "javascript-time-ago": "2.5.9",
 | 
					        "javascript-time-ago": "2.5.9",
 | 
				
			||||||
        "mux.js": "6.3.0",
 | 
					        "mux.js": "6.3.0",
 | 
				
			||||||
        "shaka-player": "4.3.4",
 | 
					        "shaka-player": "4.3.5",
 | 
				
			||||||
        "stream-browserify": "3.0.0",
 | 
					        "stream-browserify": "3.0.0",
 | 
				
			||||||
        "vue": "3.2.47",
 | 
					        "vue": "3.2.47",
 | 
				
			||||||
        "vue-i18n": "9.2.2",
 | 
					        "vue-i18n": "9.2.2",
 | 
				
			||||||
| 
						 | 
					@ -26,22 +26,22 @@
 | 
				
			||||||
        "xml-js": "1.6.11"
 | 
					        "xml-js": "1.6.11"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "devDependencies": {
 | 
					    "devDependencies": {
 | 
				
			||||||
        "@iconify/json": "2.2.27",
 | 
					        "@iconify/json": "2.2.35",
 | 
				
			||||||
        "@intlify/vite-plugin-vue-i18n": "6.0.3",
 | 
					        "@intlify/vite-plugin-vue-i18n": "6.0.3",
 | 
				
			||||||
        "@unocss/preset-icons": "0.50.0",
 | 
					        "@unocss/preset-icons": "0.50.6",
 | 
				
			||||||
        "@unocss/preset-web-fonts": "0.50.0",
 | 
					        "@unocss/preset-web-fonts": "0.50.6",
 | 
				
			||||||
        "@unocss/transformer-directives": "0.50.0",
 | 
					        "@unocss/transformer-directives": "0.50.6",
 | 
				
			||||||
        "@unocss/transformer-variant-group": "0.50.0",
 | 
					        "@unocss/transformer-variant-group": "0.50.6",
 | 
				
			||||||
        "@vitejs/plugin-legacy": "4.0.1",
 | 
					        "@vitejs/plugin-legacy": "4.0.2",
 | 
				
			||||||
        "@vitejs/plugin-vue": "4.0.0",
 | 
					        "@vitejs/plugin-vue": "4.1.0",
 | 
				
			||||||
        "@vue/compiler-sfc": "3.2.47",
 | 
					        "@vue/compiler-sfc": "3.2.47",
 | 
				
			||||||
        "eslint": "8.34.0",
 | 
					        "eslint": "8.36.0",
 | 
				
			||||||
        "eslint-config-prettier": "8.6.0",
 | 
					        "eslint-config-prettier": "8.7.0",
 | 
				
			||||||
        "eslint-plugin-prettier": "4.2.1",
 | 
					        "eslint-plugin-prettier": "4.2.1",
 | 
				
			||||||
        "eslint-plugin-vue": "9.9.0",
 | 
					        "eslint-plugin-vue": "9.9.0",
 | 
				
			||||||
        "prettier": "2.8.4",
 | 
					        "prettier": "2.8.4",
 | 
				
			||||||
        "unocss": "0.50.0",
 | 
					        "unocss": "0.50.6",
 | 
				
			||||||
        "vite": "4.1.4",
 | 
					        "vite": "4.2.0",
 | 
				
			||||||
        "vite-plugin-eslint": "1.8.1",
 | 
					        "vite-plugin-eslint": "1.8.1",
 | 
				
			||||||
        "vite-plugin-pwa": "0.14.4"
 | 
					        "vite-plugin-pwa": "0.14.4"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										13
									
								
								src/App.vue
									
										
									
									
									
								
							
							
						
						
									
										13
									
								
								src/App.vue
									
										
									
									
									
								
							| 
						 | 
					@ -1,12 +1,13 @@
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
    <div class="w-full min-h-screen px-1vw py-5 reset" :class="[theme]">
 | 
					    <div class="flex flex-col w-full min-h-screen px-1vw py-5 reset" :class="[theme]">
 | 
				
			||||||
 | 
					        <div class="flex-1">
 | 
				
			||||||
            <NavBar />
 | 
					            <NavBar />
 | 
				
			||||||
 | 
					 | 
				
			||||||
            <router-view v-slot="{ Component }">
 | 
					            <router-view v-slot="{ Component }">
 | 
				
			||||||
                <keep-alive :max="5">
 | 
					                <keep-alive :max="5">
 | 
				
			||||||
                    <component :is="Component" :key="$route.fullPath" />
 | 
					                    <component :is="Component" :key="$route.fullPath" />
 | 
				
			||||||
                </keep-alive>
 | 
					                </keep-alive>
 | 
				
			||||||
            </router-view>
 | 
					            </router-view>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <FooterComponent />
 | 
					        <FooterComponent />
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
| 
						 | 
					@ -34,6 +35,14 @@ export default {
 | 
				
			||||||
            if (themePref == "auto") this.theme = darkModePreference.matches ? "dark" : "light";
 | 
					            if (themePref == "auto") this.theme = darkModePreference.matches ? "dark" : "light";
 | 
				
			||||||
            else this.theme = themePref;
 | 
					            else this.theme = themePref;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Change title bar color based on user's theme
 | 
				
			||||||
 | 
					            const themeColor = document.querySelector("meta[name='theme-color']");
 | 
				
			||||||
 | 
					            if (this.theme === "light") {
 | 
				
			||||||
 | 
					                themeColor.setAttribute("content", "#FFF");
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                themeColor.setAttribute("content", "#0F0F0F");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Used for the scrollbar
 | 
					            // Used for the scrollbar
 | 
				
			||||||
            const root = document.querySelector(":root");
 | 
					            const root = document.querySelector(":root");
 | 
				
			||||||
            this.theme == "dark" ? root.classList.add("dark") : root.classList.remove("dark");
 | 
					            this.theme == "dark" ? root.classList.add("dark") : root.classList.remove("dark");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,18 +1,23 @@
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
    <ErrorHandler v-if="channel && channel.error" :message="channel.message" :error="channel.error" />
 | 
					    <ErrorHandler v-if="channel && channel.error" :message="channel.message" :error="channel.error" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div v-if="channel" v-show="!channel.error">
 | 
					    <LoadingIndicatorPage :show-content="channel != null && !channel.error">
 | 
				
			||||||
        <div class="flex justify-center place-items-center">
 | 
					        <img
 | 
				
			||||||
 | 
					            v-if="channel.bannerUrl"
 | 
				
			||||||
 | 
					            :src="channel.bannerUrl"
 | 
				
			||||||
 | 
					            class="w-full py-1.5 h-30 md:h-50 object-cover"
 | 
				
			||||||
 | 
					            loading="lazy"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					        <div class="flex flex-col md:flex-row justify-between items-center">
 | 
				
			||||||
 | 
					            <div class="flex place-items-center">
 | 
				
			||||||
                <img height="48" width="48" class="rounded-full m-1" :src="channel.avatarUrl" />
 | 
					                <img height="48" width="48" class="rounded-full m-1" :src="channel.avatarUrl" />
 | 
				
			||||||
            <h1 v-text="channel.name" />
 | 
					                <div class="flex gap-1 items-center">
 | 
				
			||||||
            <font-awesome-icon class="ml-1.5 !text-3xl" v-if="channel.verified" icon="check" />
 | 
					                    <h1 v-text="channel.name" class="!text-xl" />
 | 
				
			||||||
 | 
					                    <font-awesome-icon class="!text-xl" v-if="channel.verified" icon="check" />
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
        <img v-if="channel.bannerUrl" :src="channel.bannerUrl" class="w-full pb-1.5" loading="lazy" />
 | 
					 | 
				
			||||||
        <!-- eslint-disable-next-line vue/no-v-html -->
 | 
					 | 
				
			||||||
        <p class="whitespace-pre-wrap">
 | 
					 | 
				
			||||||
            <span v-html="purifyHTML(rewriteDescription(channel.description))" />
 | 
					 | 
				
			||||||
        </p>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <div class="flex gap-2">
 | 
				
			||||||
                <button
 | 
					                <button
 | 
				
			||||||
                    class="btn"
 | 
					                    class="btn"
 | 
				
			||||||
                    @click="subscribeHandler"
 | 
					                    @click="subscribeHandler"
 | 
				
			||||||
| 
						 | 
					@ -30,14 +35,30 @@
 | 
				
			||||||
                    v-if="channel.id"
 | 
					                    v-if="channel.id"
 | 
				
			||||||
                    :href="`${apiUrl()}/feed/unauthenticated/rss?channels=${channel.id}`"
 | 
					                    :href="`${apiUrl()}/feed/unauthenticated/rss?channels=${channel.id}`"
 | 
				
			||||||
                    target="_blank"
 | 
					                    target="_blank"
 | 
				
			||||||
            class="btn flex-col mx-3"
 | 
					                    class="btn flex-col"
 | 
				
			||||||
                >
 | 
					                >
 | 
				
			||||||
                    <font-awesome-icon icon="rss" />
 | 
					                    <font-awesome-icon icon="rss" />
 | 
				
			||||||
                </a>
 | 
					                </a>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <!-- eslint-disable-next-line vue/no-v-html -->
 | 
				
			||||||
 | 
					        <div v-if="channel.description" class="whitespace-pre-wrap py-2 mx-1">
 | 
				
			||||||
 | 
					            <span v-if="fullDescription" v-html="purifyHTML(rewriteDescription(channel.description))" />
 | 
				
			||||||
 | 
					            <span v-html="purifyHTML(rewriteDescription(channel.description.slice(0, 100)))" v-else />
 | 
				
			||||||
 | 
					            <span v-if="channel.description.length > 100 && !fullDescription">...</span>
 | 
				
			||||||
 | 
					            <button
 | 
				
			||||||
 | 
					                v-if="channel.description.length > 100"
 | 
				
			||||||
 | 
					                class="hover:underline font-semibold text-neutral-500 block whitespace-normal"
 | 
				
			||||||
 | 
					                @click="fullDescription = !fullDescription"
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					                [{{ fullDescription ? $t("actions.show_less") : $t("actions.show_more") }}]
 | 
				
			||||||
 | 
					            </button>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <WatchOnYouTubeButton :link="`https://youtube.com/channel/${this.channel.id}`" />
 | 
					        <WatchOnYouTubeButton :link="`https://youtube.com/channel/${this.channel.id}`" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div class="flex mt-4 mb-2">
 | 
					        <div class="flex my-2 mx-1">
 | 
				
			||||||
            <button
 | 
					            <button
 | 
				
			||||||
                v-for="(tab, index) in tabs"
 | 
					                v-for="(tab, index) in tabs"
 | 
				
			||||||
                :key="tab.name"
 | 
					                :key="tab.name"
 | 
				
			||||||
| 
						 | 
					@ -61,19 +82,21 @@
 | 
				
			||||||
                hide-channel
 | 
					                hide-channel
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
    </div>
 | 
					    </LoadingIndicatorPage>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script>
 | 
					<script>
 | 
				
			||||||
import ErrorHandler from "./ErrorHandler.vue";
 | 
					import ErrorHandler from "./ErrorHandler.vue";
 | 
				
			||||||
import ContentItem from "./ContentItem.vue";
 | 
					import ContentItem from "./ContentItem.vue";
 | 
				
			||||||
import WatchOnYouTubeButton from "./WatchOnYouTubeButton.vue";
 | 
					import WatchOnYouTubeButton from "./WatchOnYouTubeButton.vue";
 | 
				
			||||||
 | 
					import LoadingIndicatorPage from "./LoadingIndicatorPage.vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default {
 | 
					export default {
 | 
				
			||||||
    components: {
 | 
					    components: {
 | 
				
			||||||
        ErrorHandler,
 | 
					        ErrorHandler,
 | 
				
			||||||
        ContentItem,
 | 
					        ContentItem,
 | 
				
			||||||
        WatchOnYouTubeButton,
 | 
					        WatchOnYouTubeButton,
 | 
				
			||||||
 | 
					        LoadingIndicatorPage,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    data() {
 | 
					    data() {
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
| 
						 | 
					@ -82,6 +105,7 @@ export default {
 | 
				
			||||||
            tabs: [],
 | 
					            tabs: [],
 | 
				
			||||||
            selectedTab: 0,
 | 
					            selectedTab: 0,
 | 
				
			||||||
            contentItems: [],
 | 
					            contentItems: [],
 | 
				
			||||||
 | 
					            fullDescription: false,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    mounted() {
 | 
					    mounted() {
 | 
				
			||||||
| 
						 | 
					@ -121,7 +145,9 @@ export default {
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        async fetchChannel() {
 | 
					        async fetchChannel() {
 | 
				
			||||||
            const url = this.apiUrl() + "/" + this.$route.params.path + "/" + this.$route.params.channelId;
 | 
					            const url = this.$route.path.includes("@")
 | 
				
			||||||
 | 
					                ? this.apiUrl() + "/c/" + this.$route.params.channelId
 | 
				
			||||||
 | 
					                : this.apiUrl() + "/" + this.$route.params.path + "/" + this.$route.params.channelId;
 | 
				
			||||||
            return await this.fetchJson(url);
 | 
					            return await this.fetchJson(url);
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        async getChannelData() {
 | 
					        async getChannelData() {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,27 +24,29 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <hr />
 | 
					    <hr />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div class="video-grid">
 | 
					    <LoadingIndicatorPage :show-content="videosStore != null" class="video-grid">
 | 
				
			||||||
        <template v-for="video in videos" :key="video.url">
 | 
					        <template v-for="video in videos" :key="video.url">
 | 
				
			||||||
            <VideoItem v-if="shouldShowVideo(video)" :is-feed="true" :item="video" />
 | 
					            <VideoItem v-if="shouldShowVideo(video)" :is-feed="true" :item="video" />
 | 
				
			||||||
        </template>
 | 
					        </template>
 | 
				
			||||||
    </div>
 | 
					    </LoadingIndicatorPage>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script>
 | 
					<script>
 | 
				
			||||||
import VideoItem from "./VideoItem.vue";
 | 
					import VideoItem from "./VideoItem.vue";
 | 
				
			||||||
import SortingSelector from "./SortingSelector.vue";
 | 
					import SortingSelector from "./SortingSelector.vue";
 | 
				
			||||||
 | 
					import LoadingIndicatorPage from "./LoadingIndicatorPage.vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default {
 | 
					export default {
 | 
				
			||||||
    components: {
 | 
					    components: {
 | 
				
			||||||
        VideoItem,
 | 
					        VideoItem,
 | 
				
			||||||
        SortingSelector,
 | 
					        SortingSelector,
 | 
				
			||||||
 | 
					        LoadingIndicatorPage,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    data() {
 | 
					    data() {
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
            currentVideoCount: 0,
 | 
					            currentVideoCount: 0,
 | 
				
			||||||
            videoStep: 100,
 | 
					            videoStep: 100,
 | 
				
			||||||
            videosStore: [],
 | 
					            videosStore: null,
 | 
				
			||||||
            videos: [],
 | 
					            videos: [],
 | 
				
			||||||
            availableFilters: ["all", "shorts", "videos"],
 | 
					            availableFilters: ["all", "shorts", "videos"],
 | 
				
			||||||
            selectedFilter: "all",
 | 
					            selectedFilter: "all",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										55
									
								
								src/components/LoadingIndicatorPage.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/components/LoadingIndicatorPage.vue
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,55 @@
 | 
				
			||||||
 | 
					<template>
 | 
				
			||||||
 | 
					    <div v-if="!showContent" class="flex min-h-[75vh] w-full justify-center items-center">
 | 
				
			||||||
 | 
					        <span id="spinner" />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <div v-else>
 | 
				
			||||||
 | 
					        <slot />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style>
 | 
				
			||||||
 | 
					#spinner:after {
 | 
				
			||||||
 | 
					    --spinner-color: #000;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.dark #spinner:after {
 | 
				
			||||||
 | 
					    --spinner-color: #fff;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#spinner {
 | 
				
			||||||
 | 
					    display: inline-block;
 | 
				
			||||||
 | 
					    width: 70px;
 | 
				
			||||||
 | 
					    height: 70px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#spinner:after {
 | 
				
			||||||
 | 
					    content: " ";
 | 
				
			||||||
 | 
					    display: block;
 | 
				
			||||||
 | 
					    width: 54px;
 | 
				
			||||||
 | 
					    height: 54px;
 | 
				
			||||||
 | 
					    margin: 8px;
 | 
				
			||||||
 | 
					    border-radius: 50%;
 | 
				
			||||||
 | 
					    border: 4px solid var(--spinner-color);
 | 
				
			||||||
 | 
					    border-color: var(--spinner-color) transparent var(--spinner-color) transparent;
 | 
				
			||||||
 | 
					    animation: spinner 1.2s linear infinite;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@keyframes spinner {
 | 
				
			||||||
 | 
					    0% {
 | 
				
			||||||
 | 
					        transform: rotate(0deg);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    100% {
 | 
				
			||||||
 | 
					        transform: rotate(360deg);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					export default {
 | 
				
			||||||
 | 
					    props: {
 | 
				
			||||||
 | 
					        showContent: {
 | 
				
			||||||
 | 
					            type: Boolean,
 | 
				
			||||||
 | 
					            required: true,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,7 @@
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
    <ErrorHandler v-if="playlist && playlist.error" :message="playlist.message" :error="playlist.error" />
 | 
					    <ErrorHandler v-if="playlist && playlist.error" :message="playlist.message" :error="playlist.error" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div v-if="playlist" v-show="!playlist.error">
 | 
					    <LoadingIndicatorPage :show-content="playlist" v-show="!playlist.error">
 | 
				
			||||||
        <h1 class="text-center my-4" v-text="playlist.name" />
 | 
					        <h1 class="text-center my-4" v-text="playlist.name" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div class="flex justify-between items-center">
 | 
					        <div class="flex justify-between items-center">
 | 
				
			||||||
| 
						 | 
					@ -46,11 +46,12 @@
 | 
				
			||||||
                width="168"
 | 
					                width="168"
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
    </div>
 | 
					    </LoadingIndicatorPage>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script>
 | 
					<script>
 | 
				
			||||||
import ErrorHandler from "./ErrorHandler.vue";
 | 
					import ErrorHandler from "./ErrorHandler.vue";
 | 
				
			||||||
 | 
					import LoadingIndicatorPage from "./LoadingIndicatorPage.vue";
 | 
				
			||||||
import VideoItem from "./VideoItem.vue";
 | 
					import VideoItem from "./VideoItem.vue";
 | 
				
			||||||
import WatchOnYouTubeButton from "./WatchOnYouTubeButton.vue";
 | 
					import WatchOnYouTubeButton from "./WatchOnYouTubeButton.vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -59,6 +60,7 @@ export default {
 | 
				
			||||||
        ErrorHandler,
 | 
					        ErrorHandler,
 | 
				
			||||||
        VideoItem,
 | 
					        VideoItem,
 | 
				
			||||||
        WatchOnYouTubeButton,
 | 
					        WatchOnYouTubeButton,
 | 
				
			||||||
 | 
					        LoadingIndicatorPage,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    data() {
 | 
					    data() {
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
| 
						 | 
					@ -88,7 +90,7 @@ export default {
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
            }).then(json => {
 | 
					            }).then(json => {
 | 
				
			||||||
                if (json.error) alert(json.error);
 | 
					                if (json.error) alert(json.error);
 | 
				
			||||||
                else if (json.filter(playlist => playlist.id === playlistId).length > 0) this.admin = true;
 | 
					                else if (json.some(playlist => playlist.id === playlistId)) this.admin = true;
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
        this.isPlaylistBookmarked();
 | 
					        this.isPlaylistBookmarked();
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -376,6 +376,7 @@ export default {
 | 
				
			||||||
            languages: [
 | 
					            languages: [
 | 
				
			||||||
                { code: "ar", name: "Arabic" },
 | 
					                { code: "ar", name: "Arabic" },
 | 
				
			||||||
                { code: "az", name: "Azərbaycan" },
 | 
					                { code: "az", name: "Azərbaycan" },
 | 
				
			||||||
 | 
					                { code: "bg", name: "Български" },
 | 
				
			||||||
                { code: "bn", name: "বাংলা" },
 | 
					                { code: "bn", name: "বাংলা" },
 | 
				
			||||||
                { code: "bs", name: "Bosanski" },
 | 
					                { code: "bs", name: "Bosanski" },
 | 
				
			||||||
                { code: "ca", name: "Català" },
 | 
					                { code: "ca", name: "Català" },
 | 
				
			||||||
| 
						 | 
					@ -436,7 +437,7 @@ export default {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.fetchJson("https://piped-instances.kavin.rocks/").then(resp => {
 | 
					        this.fetchJson("https://piped-instances.kavin.rocks/").then(resp => {
 | 
				
			||||||
            this.instances = resp;
 | 
					            this.instances = resp;
 | 
				
			||||||
            if (this.instances.filter(instance => instance.api_url == this.apiUrl()).length == 0)
 | 
					            if (!this.instances.some(instance => instance.api_url == this.apiUrl()))
 | 
				
			||||||
                this.instances.push({
 | 
					                this.instances.push({
 | 
				
			||||||
                    name: "Custom Instance",
 | 
					                    name: "Custom Instance",
 | 
				
			||||||
                    api_url: this.apiUrl(),
 | 
					                    api_url: this.apiUrl(),
 | 
				
			||||||
| 
						 | 
					@ -615,4 +616,10 @@ export default {
 | 
				
			||||||
.pref {
 | 
					.pref {
 | 
				
			||||||
    @apply flex justify-between items-center my-2 mx-[15vw] lt-md:mx-[2vw];
 | 
					    @apply flex justify-between items-center my-2 mx-[15vw] lt-md:mx-[2vw];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					.pref:nth-child(odd) {
 | 
				
			||||||
 | 
					    @apply bg-gray-200;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.dark .pref:nth-child(odd) {
 | 
				
			||||||
 | 
					    @apply bg-dark-800;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
</style>
 | 
					</style>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,19 +18,21 @@
 | 
				
			||||||
        </i18n-t>
 | 
					        </i18n-t>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div v-if="results" class="video-grid">
 | 
					    <LoadingIndicatorPage :show-content="results != null && results.items?.length" class="video-grid">
 | 
				
			||||||
        <template v-for="result in results.items" :key="result.url">
 | 
					        <template v-for="result in results.items" :key="result.url">
 | 
				
			||||||
            <ContentItem :item="result" height="94" width="168" />
 | 
					            <ContentItem :item="result" height="94" width="168" />
 | 
				
			||||||
        </template>
 | 
					        </template>
 | 
				
			||||||
    </div>
 | 
					    </LoadingIndicatorPage>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script>
 | 
					<script>
 | 
				
			||||||
import ContentItem from "./ContentItem.vue";
 | 
					import ContentItem from "./ContentItem.vue";
 | 
				
			||||||
 | 
					import LoadingIndicatorPage from "./LoadingIndicatorPage.vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default {
 | 
					export default {
 | 
				
			||||||
    components: {
 | 
					    components: {
 | 
				
			||||||
        ContentItem,
 | 
					        ContentItem,
 | 
				
			||||||
 | 
					        LoadingIndicatorPage,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    data() {
 | 
					    data() {
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,17 +3,19 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <hr />
 | 
					    <hr />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div class="video-grid">
 | 
					    <LoadingIndicatorPage :show-content="videos.length != 0" class="video-grid">
 | 
				
			||||||
        <VideoItem v-for="video in videos" :key="video.url" :item="video" height="118" width="210" />
 | 
					        <VideoItem v-for="video in videos" :key="video.url" :item="video" height="118" width="210" />
 | 
				
			||||||
    </div>
 | 
					    </LoadingIndicatorPage>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script>
 | 
					<script>
 | 
				
			||||||
 | 
					import LoadingIndicatorPage from "./LoadingIndicatorPage.vue";
 | 
				
			||||||
import VideoItem from "./VideoItem.vue";
 | 
					import VideoItem from "./VideoItem.vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default {
 | 
					export default {
 | 
				
			||||||
    components: {
 | 
					    components: {
 | 
				
			||||||
        VideoItem,
 | 
					        VideoItem,
 | 
				
			||||||
 | 
					        LoadingIndicatorPage,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    data() {
 | 
					    data() {
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,10 +12,10 @@
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
            <div class="w-full">
 | 
					            <div class="w-full">
 | 
				
			||||||
                <img
 | 
					                <img
 | 
				
			||||||
                    class="w-full aspect-video"
 | 
					                    class="w-full aspect-video object-contain"
 | 
				
			||||||
                    :src="item.thumbnail"
 | 
					                    :src="item.thumbnail"
 | 
				
			||||||
                    :alt="item.title"
 | 
					                    :alt="item.title"
 | 
				
			||||||
                    :class="{ 'shorts-img': item.isShort }"
 | 
					                    :class="{ 'shorts-img': item.isShort, 'opacity-75': item.watched }"
 | 
				
			||||||
                    loading="lazy"
 | 
					                    loading="lazy"
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
                <!-- progress bar -->
 | 
					                <!-- progress bar -->
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -92,7 +92,7 @@ export default {
 | 
				
			||||||
        this.hotkeysPromise.then(() => {
 | 
					        this.hotkeysPromise.then(() => {
 | 
				
			||||||
            var self = this;
 | 
					            var self = this;
 | 
				
			||||||
            this.$hotkeys(
 | 
					            this.$hotkeys(
 | 
				
			||||||
                "f,m,j,k,l,c,space,up,down,left,right,0,1,2,3,4,5,6,7,8,9,shift+n,shift+,,shift+.,return",
 | 
					                "f,m,j,k,l,c,space,up,down,left,right,0,1,2,3,4,5,6,7,8,9,shift+n,shift+,,shift+.,return,.,,",
 | 
				
			||||||
                function (e, handler) {
 | 
					                function (e, handler) {
 | 
				
			||||||
                    const videoEl = self.$refs.videoEl;
 | 
					                    const videoEl = self.$refs.videoEl;
 | 
				
			||||||
                    switch (handler.key) {
 | 
					                    switch (handler.key) {
 | 
				
			||||||
| 
						 | 
					@ -191,6 +191,14 @@ export default {
 | 
				
			||||||
                        case "return":
 | 
					                        case "return":
 | 
				
			||||||
                            self.skipSegment(videoEl);
 | 
					                            self.skipSegment(videoEl);
 | 
				
			||||||
                            break;
 | 
					                            break;
 | 
				
			||||||
 | 
					                        case ".":
 | 
				
			||||||
 | 
					                            videoEl.currentTime += 0.04;
 | 
				
			||||||
 | 
					                            e.preventDefault();
 | 
				
			||||||
 | 
					                            break;
 | 
				
			||||||
 | 
					                        case ",":
 | 
				
			||||||
 | 
					                            videoEl.currentTime -= 0.04;
 | 
				
			||||||
 | 
					                            e.preventDefault();
 | 
				
			||||||
 | 
					                            break;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
| 
						 | 
					@ -206,6 +214,8 @@ export default {
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    methods: {
 | 
					    methods: {
 | 
				
			||||||
        async loadVideo() {
 | 
					        async loadVideo() {
 | 
				
			||||||
 | 
					            this.updateSponsors();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            const component = this;
 | 
					            const component = this;
 | 
				
			||||||
            const videoEl = this.$refs.videoEl;
 | 
					            const videoEl = this.$refs.videoEl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -263,9 +273,7 @@ export default {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            const MseSupport = window.MediaSource !== undefined;
 | 
					            const MseSupport = window.MediaSource !== undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            const lbry = this.getPreferenceBoolean("disableLBRY", false)
 | 
					            const lbry = null;
 | 
				
			||||||
                ? null
 | 
					 | 
				
			||||||
                : this.video.videoStreams.filter(stream => stream.quality === "LBRY")[0];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var uri;
 | 
					            var uri;
 | 
				
			||||||
            var mime;
 | 
					            var mime;
 | 
				
			||||||
| 
						 | 
					@ -275,9 +283,10 @@ export default {
 | 
				
			||||||
                mime = "application/x-mpegURL";
 | 
					                mime = "application/x-mpegURL";
 | 
				
			||||||
            } else if (this.video.audioStreams.length > 0 && !lbry && MseSupport) {
 | 
					            } else if (this.video.audioStreams.length > 0 && !lbry && MseSupport) {
 | 
				
			||||||
                if (!this.video.dash) {
 | 
					                if (!this.video.dash) {
 | 
				
			||||||
                    const dash = (
 | 
					                    const dash = (await import("../utils/DashUtils.js")).generate_dash_file_from_formats(
 | 
				
			||||||
                        await import("@/utils/DashUtils.js").then(mod => mod.default)
 | 
					                        streams,
 | 
				
			||||||
                    ).generate_dash_file_from_formats(streams, this.video.duration);
 | 
					                        this.video.duration,
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    uri = "data:application/dash+xml;charset=utf-8;base64," + btoa(dash);
 | 
					                    uri = "data:application/dash+xml;charset=utf-8;base64," + btoa(dash);
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
| 
						 | 
					@ -313,7 +322,7 @@ export default {
 | 
				
			||||||
                uri = this.video.hls;
 | 
					                uri = this.video.hls;
 | 
				
			||||||
                mime = "application/x-mpegURL";
 | 
					                mime = "application/x-mpegURL";
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                uri = this.video.videoStreams.filter(stream => stream.codec == null).slice(-1)[0].url;
 | 
					                uri = this.video.videoStreams.findLast(stream => stream.codec == null).url;
 | 
				
			||||||
                mime = "video/mp4";
 | 
					                mime = "video/mp4";
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -363,6 +372,9 @@ export default {
 | 
				
			||||||
            else this.setPlayerAttrs(this.$player, videoEl, uri, mime, this.$shaka);
 | 
					            else this.setPlayerAttrs(this.$player, videoEl, uri, mime, this.$shaka);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (noPrevPlayer) {
 | 
					            if (noPrevPlayer) {
 | 
				
			||||||
 | 
					                videoEl.addEventListener("loadeddata", () => {
 | 
				
			||||||
 | 
					                    if (document.pictureInPictureElement) videoEl.requestPictureInPicture();
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
                videoEl.addEventListener("timeupdate", () => {
 | 
					                videoEl.addEventListener("timeupdate", () => {
 | 
				
			||||||
                    const time = videoEl.currentTime;
 | 
					                    const time = videoEl.currentTime;
 | 
				
			||||||
                    this.$emit("timeupdate", time);
 | 
					                    this.$emit("timeupdate", time);
 | 
				
			||||||
| 
						 | 
					@ -647,22 +659,7 @@ export default {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (markers) markers.style.background = `linear-gradient(${array.join(",")})`;
 | 
					            if (markers) markers.style.background = `linear-gradient(${array.join(",")})`;
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        destroy(hotkeys) {
 | 
					        updateSponsors() {
 | 
				
			||||||
            if (this.$ui) {
 | 
					 | 
				
			||||||
                this.$ui.destroy();
 | 
					 | 
				
			||||||
                this.$ui = undefined;
 | 
					 | 
				
			||||||
                this.$player = undefined;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (this.$player) {
 | 
					 | 
				
			||||||
                this.$player.destroy();
 | 
					 | 
				
			||||||
                this.$player = undefined;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if (hotkeys) this.$hotkeys?.unbind();
 | 
					 | 
				
			||||||
            this.$refs.container?.querySelectorAll("div").forEach(node => node.remove());
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    watch: {
 | 
					 | 
				
			||||||
        sponsors() {
 | 
					 | 
				
			||||||
            const skipOptions = this.getPreferenceJSON("skipOptions", {});
 | 
					            const skipOptions = this.getPreferenceJSON("skipOptions", {});
 | 
				
			||||||
            this.sponsors?.segments?.forEach(segment => {
 | 
					            this.sponsors?.segments?.forEach(segment => {
 | 
				
			||||||
                const option = skipOptions[segment.category];
 | 
					                const option = skipOptions[segment.category];
 | 
				
			||||||
| 
						 | 
					@ -674,6 +671,19 @@ export default {
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					        destroy(hotkeys) {
 | 
				
			||||||
 | 
					            if (this.$ui && !document.pictureInPictureElement) {
 | 
				
			||||||
 | 
					                this.$ui.destroy();
 | 
				
			||||||
 | 
					                this.$ui = undefined;
 | 
				
			||||||
 | 
					                this.$player = undefined;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (this.$player) {
 | 
				
			||||||
 | 
					                this.$player.destroy();
 | 
				
			||||||
 | 
					                if (!document.pictureInPictureElement) this.$player = undefined;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (hotkeys) this.$hotkeys?.unbind();
 | 
				
			||||||
 | 
					            this.$refs.container?.querySelectorAll("div").forEach(node => node.remove());
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,7 +10,7 @@
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div v-if="video && !isEmbed" class="w-full">
 | 
					    <LoadingIndicatorPage :show-content="video && !isEmbed" class="w-full">
 | 
				
			||||||
        <ErrorHandler v-if="video && video.error" :message="video.message" :error="video.error" />
 | 
					        <ErrorHandler v-if="video && video.error" :message="video.message" :error="video.error" />
 | 
				
			||||||
        <Transition>
 | 
					        <Transition>
 | 
				
			||||||
            <ToastComponent v-if="shouldShowToast" @dismissed="dismiss">
 | 
					            <ToastComponent v-if="shouldShowToast" @dismissed="dismiss">
 | 
				
			||||||
| 
						 | 
					@ -20,6 +20,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div v-show="!video.error">
 | 
					        <div v-show="!video.error">
 | 
				
			||||||
            <div :class="isMobile ? 'flex-col' : 'flex'">
 | 
					            <div :class="isMobile ? 'flex-col' : 'flex'">
 | 
				
			||||||
 | 
					                <keep-alive>
 | 
				
			||||||
                    <VideoPlayer
 | 
					                    <VideoPlayer
 | 
				
			||||||
                        ref="videoPlayer"
 | 
					                        ref="videoPlayer"
 | 
				
			||||||
                        :video="video"
 | 
					                        :video="video"
 | 
				
			||||||
| 
						 | 
					@ -29,6 +30,7 @@
 | 
				
			||||||
                        @timeupdate="onTimeUpdate"
 | 
					                        @timeupdate="onTimeUpdate"
 | 
				
			||||||
                        @ended="onVideoEnded"
 | 
					                        @ended="onVideoEnded"
 | 
				
			||||||
                    />
 | 
					                    />
 | 
				
			||||||
 | 
					                </keep-alive>
 | 
				
			||||||
                <ChaptersBar
 | 
					                <ChaptersBar
 | 
				
			||||||
                    :mobileLayout="isMobile"
 | 
					                    :mobileLayout="isMobile"
 | 
				
			||||||
                    v-if="video?.chapters?.length > 0 && showChapters"
 | 
					                    v-if="video?.chapters?.length > 0 && showChapters"
 | 
				
			||||||
| 
						 | 
					@ -219,7 +221,7 @@
 | 
				
			||||||
                <hr class="sm:hidden" />
 | 
					                <hr class="sm:hidden" />
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
    </div>
 | 
					    </LoadingIndicatorPage>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script>
 | 
					<script>
 | 
				
			||||||
| 
						 | 
					@ -232,6 +234,7 @@ import PlaylistAddModal from "./PlaylistAddModal.vue";
 | 
				
			||||||
import ShareModal from "./ShareModal.vue";
 | 
					import ShareModal from "./ShareModal.vue";
 | 
				
			||||||
import PlaylistVideos from "./PlaylistVideos.vue";
 | 
					import PlaylistVideos from "./PlaylistVideos.vue";
 | 
				
			||||||
import WatchOnYouTubeButton from "./WatchOnYouTubeButton.vue";
 | 
					import WatchOnYouTubeButton from "./WatchOnYouTubeButton.vue";
 | 
				
			||||||
 | 
					import LoadingIndicatorPage from "./LoadingIndicatorPage.vue";
 | 
				
			||||||
import ToastComponent from "./ToastComponent.vue";
 | 
					import ToastComponent from "./ToastComponent.vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default {
 | 
					export default {
 | 
				
			||||||
| 
						 | 
					@ -246,14 +249,13 @@ export default {
 | 
				
			||||||
        ShareModal,
 | 
					        ShareModal,
 | 
				
			||||||
        PlaylistVideos,
 | 
					        PlaylistVideos,
 | 
				
			||||||
        WatchOnYouTubeButton,
 | 
					        WatchOnYouTubeButton,
 | 
				
			||||||
 | 
					        LoadingIndicatorPage,
 | 
				
			||||||
        ToastComponent,
 | 
					        ToastComponent,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    data() {
 | 
					    data() {
 | 
				
			||||||
        const smallViewQuery = window.matchMedia("(max-width: 640px)");
 | 
					        const smallViewQuery = window.matchMedia("(max-width: 640px)");
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
            video: {
 | 
					            video: null,
 | 
				
			||||||
                title: "Loading...",
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            playlistId: null,
 | 
					            playlistId: null,
 | 
				
			||||||
            playlist: null,
 | 
					            playlist: null,
 | 
				
			||||||
            index: null,
 | 
					            index: null,
 | 
				
			||||||
| 
						 | 
					@ -361,7 +363,7 @@ export default {
 | 
				
			||||||
        this.showDesc = !this.getPreferenceBoolean("minimizeDescription", false);
 | 
					        this.showDesc = !this.getPreferenceBoolean("minimizeDescription", false);
 | 
				
			||||||
        this.showRecs = !this.getPreferenceBoolean("minimizeRecommendations", false);
 | 
					        this.showRecs = !this.getPreferenceBoolean("minimizeRecommendations", false);
 | 
				
			||||||
        this.showChapters = !this.getPreferenceBoolean("minimizeChapters", false);
 | 
					        this.showChapters = !this.getPreferenceBoolean("minimizeChapters", false);
 | 
				
			||||||
        if (this.video.duration) {
 | 
					        if (this.video?.duration) {
 | 
				
			||||||
            document.title = this.video.title + " - Piped";
 | 
					            document.title = this.video.title + " - Piped";
 | 
				
			||||||
            this.$refs.videoPlayer.loadVideo();
 | 
					            this.$refs.videoPlayer.loadVideo();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,10 +4,10 @@
 | 
				
			||||||
        "login": "تسجيل الدخول",
 | 
					        "login": "تسجيل الدخول",
 | 
				
			||||||
        "register": "إنشاء حساب",
 | 
					        "register": "إنشاء حساب",
 | 
				
			||||||
        "preferences": "الإعدادات",
 | 
					        "preferences": "الإعدادات",
 | 
				
			||||||
        "history": "تاريخ التصفح",
 | 
					        "history": "سجل المشاهدة",
 | 
				
			||||||
        "subscriptions": "الاشتراكات",
 | 
					        "subscriptions": "الاشتراكات",
 | 
				
			||||||
        "playlists": "قوائم التشغيل",
 | 
					        "playlists": "قوائم التشغيل",
 | 
				
			||||||
        "feed": "التغذية",
 | 
					        "feed": "محتوى الاشتراكات",
 | 
				
			||||||
        "account": "الحساب",
 | 
					        "account": "الحساب",
 | 
				
			||||||
        "instance": "الخادم",
 | 
					        "instance": "الخادم",
 | 
				
			||||||
        "player": "المشغل",
 | 
					        "player": "المشغل",
 | 
				
			||||||
| 
						 | 
					@ -127,7 +127,8 @@
 | 
				
			||||||
        "skip_button_only": "إظهار زر التخطي",
 | 
					        "skip_button_only": "إظهار زر التخطي",
 | 
				
			||||||
        "skip_automatically": "تلقائيا",
 | 
					        "skip_automatically": "تلقائيا",
 | 
				
			||||||
        "min_segment_length": "الحد الأدنى لطول الفصل (بالثواني)",
 | 
					        "min_segment_length": "الحد الأدنى لطول الفصل (بالثواني)",
 | 
				
			||||||
        "skip_segment": "تخطي الجزء"
 | 
					        "skip_segment": "تخطي الجزء",
 | 
				
			||||||
 | 
					        "show_less": "عرض أقل"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "video": {
 | 
					    "video": {
 | 
				
			||||||
        "sponsor_segments": "المقاطع الإعلانية",
 | 
					        "sponsor_segments": "المقاطع الإعلانية",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										168
									
								
								src/locales/bg.json
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								src/locales/bg.json
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,168 @@
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    "titles": {
 | 
				
			||||||
 | 
					        "channels": "Канали",
 | 
				
			||||||
 | 
					        "login": "Вход",
 | 
				
			||||||
 | 
					        "register": "Регистрация",
 | 
				
			||||||
 | 
					        "feed": "Абонаменти",
 | 
				
			||||||
 | 
					        "history": "История",
 | 
				
			||||||
 | 
					        "playlists": "Плейлисти",
 | 
				
			||||||
 | 
					        "instance": "Инстанция",
 | 
				
			||||||
 | 
					        "player": "Плейър",
 | 
				
			||||||
 | 
					        "livestreams": "Излъчвания на живо",
 | 
				
			||||||
 | 
					        "bookmarks": "Отметки",
 | 
				
			||||||
 | 
					        "trending": "Набиращи популярност",
 | 
				
			||||||
 | 
					        "account": "Профил",
 | 
				
			||||||
 | 
					        "preferences": "Настройки",
 | 
				
			||||||
 | 
					        "subscriptions": "Абонаменти"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "actions": {
 | 
				
			||||||
 | 
					        "most_recent": "Най-скорошен",
 | 
				
			||||||
 | 
					        "unsubscribe": "Отписване - {count}",
 | 
				
			||||||
 | 
					        "uses_api_from": "Използва API от ",
 | 
				
			||||||
 | 
					        "skip_sponsors": "Пропускане на спонсори",
 | 
				
			||||||
 | 
					        "skip_preview": "Пропускане на преглед/обобщение",
 | 
				
			||||||
 | 
					        "skip_self_promo": "Пропускане на самореклама/неплатена реклама",
 | 
				
			||||||
 | 
					        "min_segment_length": "Минимална дължина на сегмента (в секунди)",
 | 
				
			||||||
 | 
					        "default_quality": "Качество по подразбиране",
 | 
				
			||||||
 | 
					        "minimize_comments_default": "Минимизиране на коментарите по подразбиране",
 | 
				
			||||||
 | 
					        "subscribe": "Абониране - {count}",
 | 
				
			||||||
 | 
					        "view_subscriptions": "Преглед на абонаменти",
 | 
				
			||||||
 | 
					        "sort_by": "Сортиране по:",
 | 
				
			||||||
 | 
					        "least_recent": "Най-малко скорошен",
 | 
				
			||||||
 | 
					        "channel_name_asc": "Име на канал (А-Я)",
 | 
				
			||||||
 | 
					        "channel_name_desc": "Име на канал (Я-А)",
 | 
				
			||||||
 | 
					        "back": "Назад",
 | 
				
			||||||
 | 
					        "enable_sponsorblock": "Активиране на SponsorBlock",
 | 
				
			||||||
 | 
					        "skip_button_only": "Показване на бутона за пропускане",
 | 
				
			||||||
 | 
					        "skip_automatically": "Автоматично",
 | 
				
			||||||
 | 
					        "skip_intro": "Пропускане на прекъсване/въвеждаща анимация",
 | 
				
			||||||
 | 
					        "skip_outro": "Пропускане на крайни карти/надписи",
 | 
				
			||||||
 | 
					        "skip_interaction": "Пропускане на напомняне за абониране",
 | 
				
			||||||
 | 
					        "skip_non_music": "Попускане Немузикален раздел в музика",
 | 
				
			||||||
 | 
					        "skip_highlight": "Пропускане на видео акцент",
 | 
				
			||||||
 | 
					        "show_markers": "Показване на маркери в плейъра",
 | 
				
			||||||
 | 
					        "skip_segment": "Пропускане на сегмент",
 | 
				
			||||||
 | 
					        "theme": "Тема",
 | 
				
			||||||
 | 
					        "auto": "Автоматично",
 | 
				
			||||||
 | 
					        "dark": "Тъмна",
 | 
				
			||||||
 | 
					        "light": "Светла",
 | 
				
			||||||
 | 
					        "autoplay_video": "Автоматично пускане на видео",
 | 
				
			||||||
 | 
					        "audio_only": "Само аудио",
 | 
				
			||||||
 | 
					        "buffering_goal": "Буфериране (в секунди)",
 | 
				
			||||||
 | 
					        "country_selection": "Избор на държава",
 | 
				
			||||||
 | 
					        "default_homepage": "Начална страница по подразбиране",
 | 
				
			||||||
 | 
					        "minimize_description_default": "Минимизиране на описанието по подразбиране",
 | 
				
			||||||
 | 
					        "store_watch_history": "Запазване на историята на гледане",
 | 
				
			||||||
 | 
					        "language_selection": "Избор на език",
 | 
				
			||||||
 | 
					        "instances_list": "Списък на инстанциите",
 | 
				
			||||||
 | 
					        "enabled_codecs": "Разрешени кодеци (множество)",
 | 
				
			||||||
 | 
					        "instance_selection": "Избор на инстанция",
 | 
				
			||||||
 | 
					        "show_more": "Покажи повече",
 | 
				
			||||||
 | 
					        "yes": "Да",
 | 
				
			||||||
 | 
					        "no": "Не",
 | 
				
			||||||
 | 
					        "export_to_json": "Експорт в JSON",
 | 
				
			||||||
 | 
					        "import_from_json": "Импорт от JSON/CSV",
 | 
				
			||||||
 | 
					        "loop_this_video": "Повтаряне на това видео",
 | 
				
			||||||
 | 
					        "auto_play_next_video": "Автоматично пускане на следващото видео",
 | 
				
			||||||
 | 
					        "donations": "Дарения за разработка",
 | 
				
			||||||
 | 
					        "minimize_comments": "Минимизиране на коментарите",
 | 
				
			||||||
 | 
					        "show_comments": "Показване на коментарите",
 | 
				
			||||||
 | 
					        "show_description": "Показване на описание",
 | 
				
			||||||
 | 
					        "search": "Търси",
 | 
				
			||||||
 | 
					        "minimize_description": "Минимизиране на описание",
 | 
				
			||||||
 | 
					        "filter": "Филтър",
 | 
				
			||||||
 | 
					        "clear_history": "Изчистване на историята",
 | 
				
			||||||
 | 
					        "minimize_recommendations": "Минимизиране на препоръчани",
 | 
				
			||||||
 | 
					        "show_recommendations": "Показване на препоръчани",
 | 
				
			||||||
 | 
					        "view_ssl_score": "Преглед на SSL резултат",
 | 
				
			||||||
 | 
					        "loading": "Зареждане...",
 | 
				
			||||||
 | 
					        "hide_replies": "Скрий отговорите",
 | 
				
			||||||
 | 
					        "load_more_replies": "Зареди още отговори",
 | 
				
			||||||
 | 
					        "remove_from_playlist": "Премахване от плейлист",
 | 
				
			||||||
 | 
					        "create_playlist": "Създаване на плейлист",
 | 
				
			||||||
 | 
					        "reset_preferences": "Нулиране на настройките",
 | 
				
			||||||
 | 
					        "with_timecode": "Сподели с текущото време",
 | 
				
			||||||
 | 
					        "piped_link": "Piped връзка",
 | 
				
			||||||
 | 
					        "documentation": "Документация",
 | 
				
			||||||
 | 
					        "delete_account": "Изтрий акаунта",
 | 
				
			||||||
 | 
					        "download_as_txt": "Изтегляне като .txt",
 | 
				
			||||||
 | 
					        "share": "Сподели",
 | 
				
			||||||
 | 
					        "follow_link": "Последвай връзката",
 | 
				
			||||||
 | 
					        "add_to_playlist": "Добави към плейлист",
 | 
				
			||||||
 | 
					        "delete_playlist_video_confirm": "Да се премахне ли видеото от плейлиста?",
 | 
				
			||||||
 | 
					        "show_watch_on_youtube": "Показване на бутона \"Гледай в YouTube\"",
 | 
				
			||||||
 | 
					        "source_code": "Изходен код",
 | 
				
			||||||
 | 
					        "minimize_chapters_default": "Минимизиране на разделите по подразбиране",
 | 
				
			||||||
 | 
					        "minimize_recommendations_default": "Минимизиране на препоръчани по подразбиране",
 | 
				
			||||||
 | 
					        "show_chapters": "Раздели",
 | 
				
			||||||
 | 
					        "logout": "Отписване от това устройство",
 | 
				
			||||||
 | 
					        "clone_playlist": "Клониране на плейлист",
 | 
				
			||||||
 | 
					        "clone_playlist_success": "Успешно клониране!",
 | 
				
			||||||
 | 
					        "backup_preferences": "Архивиране на настройките",
 | 
				
			||||||
 | 
					        "rename_playlist": "Преименуване на плейлиста",
 | 
				
			||||||
 | 
					        "new_playlist_name": "Ново име на плейлиста",
 | 
				
			||||||
 | 
					        "back_to_home": "Обратно към начална страница",
 | 
				
			||||||
 | 
					        "status_page": "Статус",
 | 
				
			||||||
 | 
					        "copy_link": "Копирай връзката",
 | 
				
			||||||
 | 
					        "time_code": "Текущо време (в секунди)",
 | 
				
			||||||
 | 
					        "reply_count": "{count} отговора",
 | 
				
			||||||
 | 
					        "restore_preferences": "Възстановяване на настройките",
 | 
				
			||||||
 | 
					        "invalidate_session": "Отписване от всички устройства",
 | 
				
			||||||
 | 
					        "different_auth_instance": "Използване на различна инстанция за удостоверяване",
 | 
				
			||||||
 | 
					        "store_search_history": "Запазване на историята на търсене",
 | 
				
			||||||
 | 
					        "instance_auth_selection": "Избор на инстанция за удостоверяване",
 | 
				
			||||||
 | 
					        "confirm_reset_preferences": "Сигурни ли сте, че искате да нулирате настройките?",
 | 
				
			||||||
 | 
					        "hide_watched": "Скриване на гледани видеоклипове в Абонаменти"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "player": {
 | 
				
			||||||
 | 
					        "watch_on": "Гледай в {0}"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "login": {
 | 
				
			||||||
 | 
					        "username": "Потребителско име",
 | 
				
			||||||
 | 
					        "password": "Парола"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "video": {
 | 
				
			||||||
 | 
					        "videos": "Видеоклипове",
 | 
				
			||||||
 | 
					        "views": "{views} показвания",
 | 
				
			||||||
 | 
					        "chapters": "Раздели",
 | 
				
			||||||
 | 
					        "all": "Всички",
 | 
				
			||||||
 | 
					        "watched": "Гледани",
 | 
				
			||||||
 | 
					        "category": "Категория"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "preferences": {
 | 
				
			||||||
 | 
					        "version": "Версия",
 | 
				
			||||||
 | 
					        "registered_users": "Регистрирани потребители",
 | 
				
			||||||
 | 
					        "instance_locations": "Местоположения на инстанция",
 | 
				
			||||||
 | 
					        "instance_name": "Име на инстанция",
 | 
				
			||||||
 | 
					        "has_cdn": "Има ли CDN?",
 | 
				
			||||||
 | 
					        "up_to_date": "Актуален?",
 | 
				
			||||||
 | 
					        "ssl_score": "SSL резултат"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "comment": {
 | 
				
			||||||
 | 
					        "disabled": "Коментарите са деактивирани.",
 | 
				
			||||||
 | 
					        "pinned_by": "Фиксиран от {author}",
 | 
				
			||||||
 | 
					        "loading": "Коментарите се зареждат...",
 | 
				
			||||||
 | 
					        "user_disabled": "Коментарите са деактивирани в настройките."
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "search": {
 | 
				
			||||||
 | 
					        "did_you_mean": "Имахте предвид: {0}?",
 | 
				
			||||||
 | 
					        "all": "YouTube: Всички",
 | 
				
			||||||
 | 
					        "videos": "YouTube: Видеоклипове",
 | 
				
			||||||
 | 
					        "channels": "YouTube: Канали",
 | 
				
			||||||
 | 
					        "playlists": "YouTube: Плейлисти",
 | 
				
			||||||
 | 
					        "music_songs": "YT Music: Песни",
 | 
				
			||||||
 | 
					        "music_videos": "YT Music: Видеоклипове",
 | 
				
			||||||
 | 
					        "music_albums": "YT Music: Албуми",
 | 
				
			||||||
 | 
					        "music_playlists": "YT Music: Плейлисти"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "subscriptions": {
 | 
				
			||||||
 | 
					        "subscribed_channels_count": "Абониран за: {0}"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "info": {
 | 
				
			||||||
 | 
					        "page_not_found": "Страницата не е намерена",
 | 
				
			||||||
 | 
					        "copied": "Копирано!",
 | 
				
			||||||
 | 
					        "cannot_copy": "Не може да се копира!",
 | 
				
			||||||
 | 
					        "local_storage": "Това действие изисква localStorage, разрешени ли са бисквитките?",
 | 
				
			||||||
 | 
					        "register_no_email_note": "Използването на имейл като потребителско име не се препоръчва. Продължете все пак?"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -104,7 +104,11 @@
 | 
				
			||||||
        "show_watch_on_youtube": "Schaltfläche „Auf YouTube ansehen“ anzeigen",
 | 
					        "show_watch_on_youtube": "Schaltfläche „Auf YouTube ansehen“ anzeigen",
 | 
				
			||||||
        "with_playlist": "Mit Wiedergabeliste teilen",
 | 
					        "with_playlist": "Mit Wiedergabeliste teilen",
 | 
				
			||||||
        "playlist_bookmarked": "Markiert",
 | 
					        "playlist_bookmarked": "Markiert",
 | 
				
			||||||
        "bookmark_playlist": "Lesezeichen"
 | 
					        "bookmark_playlist": "Lesezeichen",
 | 
				
			||||||
 | 
					        "skip_segment": "Segment überspringen",
 | 
				
			||||||
 | 
					        "skip_automatically": "Automatisch",
 | 
				
			||||||
 | 
					        "min_segment_length": "Minimale Segmentlänge (in Sekunden)",
 | 
				
			||||||
 | 
					        "skip_button_only": "Überspringen-Schaltfläche anzeigen"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "player": {
 | 
					    "player": {
 | 
				
			||||||
        "watch_on": "Auf {0} ansehen"
 | 
					        "watch_on": "Auf {0} ansehen"
 | 
				
			||||||
| 
						 | 
					@ -134,7 +138,8 @@
 | 
				
			||||||
        "live": "{0} Live",
 | 
					        "live": "{0} Live",
 | 
				
			||||||
        "chapters": "Kapitel",
 | 
					        "chapters": "Kapitel",
 | 
				
			||||||
        "shorts": "Shorts",
 | 
					        "shorts": "Shorts",
 | 
				
			||||||
        "all": "Alle"
 | 
					        "all": "Alle",
 | 
				
			||||||
 | 
					        "category": "Kategorie"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "preferences": {
 | 
					    "preferences": {
 | 
				
			||||||
        "ssl_score": "SSL-Bewertung",
 | 
					        "ssl_score": "SSL-Bewertung",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -129,7 +129,9 @@
 | 
				
			||||||
        "with_playlist": "Share with playlist",
 | 
					        "with_playlist": "Share with playlist",
 | 
				
			||||||
        "bookmark_playlist": "Bookmark",
 | 
					        "bookmark_playlist": "Bookmark",
 | 
				
			||||||
        "playlist_bookmarked": "Bookmarked",
 | 
					        "playlist_bookmarked": "Bookmarked",
 | 
				
			||||||
        "dismiss": "Dismiss"
 | 
					        "dismiss": "Dismiss",
 | 
				
			||||||
 | 
					        "show_more": "Show more",
 | 
				
			||||||
 | 
					        "show_less": "Show less"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "comment": {
 | 
					    "comment": {
 | 
				
			||||||
        "pinned_by": "Pinned by {author}",
 | 
					        "pinned_by": "Pinned by {author}",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,7 +42,7 @@
 | 
				
			||||||
        "instance_selection": "Selección de instancias",
 | 
					        "instance_selection": "Selección de instancias",
 | 
				
			||||||
        "enabled_codecs": "Códecs habilitados (múltiples)",
 | 
					        "enabled_codecs": "Códecs habilitados (múltiples)",
 | 
				
			||||||
        "instances_list": "Lista de instancias",
 | 
					        "instances_list": "Lista de instancias",
 | 
				
			||||||
        "language_selection": "Selección de lenguajes",
 | 
					        "language_selection": "Selección de idioma",
 | 
				
			||||||
        "store_watch_history": "Recordar historial de visualización",
 | 
					        "store_watch_history": "Recordar historial de visualización",
 | 
				
			||||||
        "minimize_description_default": "Minimizar la descripción por defecto",
 | 
					        "minimize_description_default": "Minimizar la descripción por defecto",
 | 
				
			||||||
        "show_comments": "Mostrar comentarios",
 | 
					        "show_comments": "Mostrar comentarios",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -120,7 +120,11 @@
 | 
				
			||||||
        "no_valid_playlists": "Le fichier ne contient pas de listes de lecture valides !",
 | 
					        "no_valid_playlists": "Le fichier ne contient pas de listes de lecture valides !",
 | 
				
			||||||
        "bookmark_playlist": "Marque-page",
 | 
					        "bookmark_playlist": "Marque-page",
 | 
				
			||||||
        "playlist_bookmarked": "Dans les marque-pages",
 | 
					        "playlist_bookmarked": "Dans les marque-pages",
 | 
				
			||||||
        "with_playlist": "Partager avec la liste de lecture"
 | 
					        "with_playlist": "Partager avec la liste de lecture",
 | 
				
			||||||
 | 
					        "skip_button_only": "Afficher le bouton de saut",
 | 
				
			||||||
 | 
					        "skip_automatically": "Automatiquement",
 | 
				
			||||||
 | 
					        "min_segment_length": "Longueur minimale du segment (en secondes)",
 | 
				
			||||||
 | 
					        "skip_segment": "Sauter le segment"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "player": {
 | 
					    "player": {
 | 
				
			||||||
        "watch_on": "Regarder sur {0}"
 | 
					        "watch_on": "Regarder sur {0}"
 | 
				
			||||||
| 
						 | 
					@ -134,7 +138,8 @@
 | 
				
			||||||
        "chapters": "Chapitres",
 | 
					        "chapters": "Chapitres",
 | 
				
			||||||
        "live": "{0} en direct",
 | 
					        "live": "{0} en direct",
 | 
				
			||||||
        "shorts": "Courtes",
 | 
					        "shorts": "Courtes",
 | 
				
			||||||
        "all": "Tout"
 | 
					        "all": "Tout",
 | 
				
			||||||
 | 
					        "category": "Catégorie"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "preferences": {
 | 
					    "preferences": {
 | 
				
			||||||
        "ssl_score": "Score SSL",
 | 
					        "ssl_score": "Score SSL",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -53,7 +53,7 @@
 | 
				
			||||||
        "instances_list": "רשימת עותקים",
 | 
					        "instances_list": "רשימת עותקים",
 | 
				
			||||||
        "enabled_codecs": "מפענחים פעילים (מגוון)",
 | 
					        "enabled_codecs": "מפענחים פעילים (מגוון)",
 | 
				
			||||||
        "instance_selection": "בחירת עותק",
 | 
					        "instance_selection": "בחירת עותק",
 | 
				
			||||||
        "show_more": "להציג עוד",
 | 
					        "show_more": "להציג יותר",
 | 
				
			||||||
        "yes": "כן",
 | 
					        "yes": "כן",
 | 
				
			||||||
        "no": "לא",
 | 
					        "no": "לא",
 | 
				
			||||||
        "export_to_json": "ייצוא ל־JSON",
 | 
					        "export_to_json": "ייצוא ל־JSON",
 | 
				
			||||||
| 
						 | 
					@ -127,7 +127,8 @@
 | 
				
			||||||
        "skip_button_only": "הצגת כפתור דילוג",
 | 
					        "skip_button_only": "הצגת כפתור דילוג",
 | 
				
			||||||
        "min_segment_length": "אורך מקטע מזערי (בשניות)",
 | 
					        "min_segment_length": "אורך מקטע מזערי (בשניות)",
 | 
				
			||||||
        "skip_segment": "דילוג על מקטע",
 | 
					        "skip_segment": "דילוג על מקטע",
 | 
				
			||||||
        "skip_automatically": "אוטומטית"
 | 
					        "skip_automatically": "אוטומטית",
 | 
				
			||||||
 | 
					        "show_less": "להציג פחות"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "comment": {
 | 
					    "comment": {
 | 
				
			||||||
        "pinned_by": "ננעץ על ידי {author}",
 | 
					        "pinned_by": "ננעץ על ידי {author}",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,7 +8,8 @@
 | 
				
			||||||
        "chapters": "Poglavlja",
 | 
					        "chapters": "Poglavlja",
 | 
				
			||||||
        "live": "{0} uživo",
 | 
					        "live": "{0} uživo",
 | 
				
			||||||
        "shorts": "Kratka videa",
 | 
					        "shorts": "Kratka videa",
 | 
				
			||||||
        "all": "Sva"
 | 
					        "all": "Sva",
 | 
				
			||||||
 | 
					        "category": "Kategorija"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "preferences": {
 | 
					    "preferences": {
 | 
				
			||||||
        "ssl_score": "SSL ocjena",
 | 
					        "ssl_score": "SSL ocjena",
 | 
				
			||||||
| 
						 | 
					@ -92,7 +93,7 @@
 | 
				
			||||||
        "select_playlist": "Odaberi popis snimaka",
 | 
					        "select_playlist": "Odaberi popis snimaka",
 | 
				
			||||||
        "please_select_playlist": "Odaberi popis snimaka",
 | 
					        "please_select_playlist": "Odaberi popis snimaka",
 | 
				
			||||||
        "delete_playlist_video_confirm": "Ukloniti video iz popisa snimaka?",
 | 
					        "delete_playlist_video_confirm": "Ukloniti video iz popisa snimaka?",
 | 
				
			||||||
        "show_markers": "Prikaži oznake na Pokretaču",
 | 
					        "show_markers": "Prikaži oznake na playeru",
 | 
				
			||||||
        "delete_account": "Izbriši račun",
 | 
					        "delete_account": "Izbriši račun",
 | 
				
			||||||
        "logout": "Odjavi se s ovog uređaja",
 | 
					        "logout": "Odjavi se s ovog uređaja",
 | 
				
			||||||
        "minimize_recommendations_default": "Standardno sakrij preporuke",
 | 
					        "minimize_recommendations_default": "Standardno sakrij preporuke",
 | 
				
			||||||
| 
						 | 
					@ -130,7 +131,11 @@
 | 
				
			||||||
        "no_valid_playlists": "Datoteka ne sadrži ispravne popise snimaka!",
 | 
					        "no_valid_playlists": "Datoteka ne sadrži ispravne popise snimaka!",
 | 
				
			||||||
        "with_playlist": "Dijeli s popisom snimaka",
 | 
					        "with_playlist": "Dijeli s popisom snimaka",
 | 
				
			||||||
        "playlist_bookmarked": "Zabilježeno",
 | 
					        "playlist_bookmarked": "Zabilježeno",
 | 
				
			||||||
        "bookmark_playlist": "Zabilježi"
 | 
					        "bookmark_playlist": "Zabilježi",
 | 
				
			||||||
 | 
					        "skip_button_only": "Prikaži gumb za preskakanje",
 | 
				
			||||||
 | 
					        "skip_automatically": "Automatski",
 | 
				
			||||||
 | 
					        "skip_segment": "Preskoči segment",
 | 
				
			||||||
 | 
					        "min_segment_length": "Najmanja duljina segmenta (u sekundama)"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "player": {
 | 
					    "player": {
 | 
				
			||||||
        "watch_on": "Gledaj na {0}"
 | 
					        "watch_on": "Gledaj na {0}"
 | 
				
			||||||
| 
						 | 
					@ -146,7 +151,7 @@
 | 
				
			||||||
        "playlists": "Popisi snimaka",
 | 
					        "playlists": "Popisi snimaka",
 | 
				
			||||||
        "account": "Račun",
 | 
					        "account": "Račun",
 | 
				
			||||||
        "instance": "Instanca",
 | 
					        "instance": "Instanca",
 | 
				
			||||||
        "player": "Pokretač",
 | 
					        "player": "Player",
 | 
				
			||||||
        "channels": "Kanali",
 | 
					        "channels": "Kanali",
 | 
				
			||||||
        "livestreams": "Prijenosi uživo",
 | 
					        "livestreams": "Prijenosi uživo",
 | 
				
			||||||
        "bookmarks": "Zabilješke"
 | 
					        "bookmarks": "Zabilješke"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -138,7 +138,8 @@
 | 
				
			||||||
        "live": "{0} Diretta",
 | 
					        "live": "{0} Diretta",
 | 
				
			||||||
        "chapters": "Capitoli",
 | 
					        "chapters": "Capitoli",
 | 
				
			||||||
        "shorts": "Short",
 | 
					        "shorts": "Short",
 | 
				
			||||||
        "all": "Tutti"
 | 
					        "all": "Tutti",
 | 
				
			||||||
 | 
					        "category": "Categoria"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "preferences": {
 | 
					    "preferences": {
 | 
				
			||||||
        "ssl_score": "Valutazione SSL",
 | 
					        "ssl_score": "Valutazione SSL",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,13 +29,13 @@
 | 
				
			||||||
        "channel_name_desc": "チャンネル名 (ZからA)",
 | 
					        "channel_name_desc": "チャンネル名 (ZからA)",
 | 
				
			||||||
        "back": "戻る",
 | 
					        "back": "戻る",
 | 
				
			||||||
        "uses_api_from": "API使用元 ",
 | 
					        "uses_api_from": "API使用元 ",
 | 
				
			||||||
        "enable_sponsorblock": "SponsorBlockを有効化",
 | 
					        "enable_sponsorblock": "SponsorBlock を有効化",
 | 
				
			||||||
        "skip_sponsors": "広告をスキップ",
 | 
					        "skip_sponsors": "広告をスキップ",
 | 
				
			||||||
        "skip_intro": "休止時間/イントロ画面をスキップ",
 | 
					        "skip_intro": "休止時間/導入アニメをスキップ",
 | 
				
			||||||
        "skip_outro": "終了画面/クレジットをスキップ",
 | 
					        "skip_outro": "終了シーン/クレジットをスキップ",
 | 
				
			||||||
        "skip_preview": "プレビュー/要約をスキップ",
 | 
					        "skip_preview": "プレビュー/要約をスキップ",
 | 
				
			||||||
        "skip_interaction": "チャンネル登録など操作を求める自己宣伝をスキップ",
 | 
					        "skip_interaction": "チャンネル登録など操作を求める自己宣伝をスキップ",
 | 
				
			||||||
        "skip_self_promo": "無償/自己プロモーションをスキップ",
 | 
					        "skip_self_promo": "無報酬/自己の宣伝をスキップ",
 | 
				
			||||||
        "skip_non_music": "音楽: 非音楽部分をスキップ",
 | 
					        "skip_non_music": "音楽: 非音楽部分をスキップ",
 | 
				
			||||||
        "theme": "テーマ",
 | 
					        "theme": "テーマ",
 | 
				
			||||||
        "auto": "自動",
 | 
					        "auto": "自動",
 | 
				
			||||||
| 
						 | 
					@ -43,12 +43,12 @@
 | 
				
			||||||
        "light": "ライト",
 | 
					        "light": "ライト",
 | 
				
			||||||
        "autoplay_video": "動画を自動再生",
 | 
					        "autoplay_video": "動画を自動再生",
 | 
				
			||||||
        "audio_only": "音声のみ",
 | 
					        "audio_only": "音声のみ",
 | 
				
			||||||
        "default_quality": "デフォルトの画質",
 | 
					        "default_quality": "標準の画質",
 | 
				
			||||||
        "buffering_goal": "バッファリング目標値 (秒)",
 | 
					        "buffering_goal": "バッファリング目標値 (秒)",
 | 
				
			||||||
        "country_selection": "国の選択",
 | 
					        "country_selection": "国の選択",
 | 
				
			||||||
        "default_homepage": "ホームに表示するページ",
 | 
					        "default_homepage": "ホームに表示するページ",
 | 
				
			||||||
        "show_comments": "コメントを表示",
 | 
					        "show_comments": "コメントを表示",
 | 
				
			||||||
        "minimize_description_default": "デフォルトで詳細を最小化する",
 | 
					        "minimize_description_default": "最初から説明を最小化",
 | 
				
			||||||
        "store_watch_history": "再生履歴を保存する",
 | 
					        "store_watch_history": "再生履歴を保存する",
 | 
				
			||||||
        "language_selection": "言語の選択",
 | 
					        "language_selection": "言語の選択",
 | 
				
			||||||
        "instances_list": "インスタンス一覧",
 | 
					        "instances_list": "インスタンス一覧",
 | 
				
			||||||
| 
						 | 
					@ -68,16 +68,16 @@
 | 
				
			||||||
        "show_recommendations": "おすすめを見る",
 | 
					        "show_recommendations": "おすすめを見る",
 | 
				
			||||||
        "disable_lbry": "ストリーミングのLBRYを無効化",
 | 
					        "disable_lbry": "ストリーミングのLBRYを無効化",
 | 
				
			||||||
        "enable_lbry_proxy": "LBRYプロキシをオン",
 | 
					        "enable_lbry_proxy": "LBRYプロキシをオン",
 | 
				
			||||||
        "view_ssl_score": "SSLスコアを見る",
 | 
					        "view_ssl_score": "SSLの評価を表示",
 | 
				
			||||||
        "search": "検索",
 | 
					        "search": "検索",
 | 
				
			||||||
        "filter": "フィルター",
 | 
					        "filter": "フィルター",
 | 
				
			||||||
        "loading": "読み込み中…",
 | 
					        "loading": "読み込み中…",
 | 
				
			||||||
        "clear_history": "再生履歴を削除",
 | 
					        "clear_history": "再生履歴を削除",
 | 
				
			||||||
        "hide_replies": "返信を非表示",
 | 
					        "hide_replies": "返信を非表示",
 | 
				
			||||||
        "load_more_replies": "返信をもっと見る",
 | 
					        "load_more_replies": "返信をもっと見る",
 | 
				
			||||||
        "skip_filler_tangent": "無関係なコンテンツをスキップ",
 | 
					        "skip_filler_tangent": "無関係な談話をスキップ",
 | 
				
			||||||
        "skip_highlight": "ハイライトをスキップ",
 | 
					        "skip_highlight": "ハイライトをスキップ",
 | 
				
			||||||
        "add_to_playlist": "再生リストに追加する",
 | 
					        "add_to_playlist": "再生リストに追加",
 | 
				
			||||||
        "create_playlist": "再生リストを作成",
 | 
					        "create_playlist": "再生リストを作成",
 | 
				
			||||||
        "remove_from_playlist": "再生リストから削除",
 | 
					        "remove_from_playlist": "再生リストから削除",
 | 
				
			||||||
        "delete_playlist_video_confirm": "再生リストからこの動画を削除しますか?",
 | 
					        "delete_playlist_video_confirm": "再生リストからこの動画を削除しますか?",
 | 
				
			||||||
| 
						 | 
					@ -98,9 +98,9 @@
 | 
				
			||||||
        "different_auth_instance": "認証に別のインスタンスを使う",
 | 
					        "different_auth_instance": "認証に別のインスタンスを使う",
 | 
				
			||||||
        "download_as_txt": ".txtでダウンロード",
 | 
					        "download_as_txt": ".txtでダウンロード",
 | 
				
			||||||
        "logout": "このデバイスでログアウト",
 | 
					        "logout": "このデバイスでログアウト",
 | 
				
			||||||
        "minimize_recommendations_default": "デフォルトでおすすめを最小化する",
 | 
					        "minimize_recommendations_default": "最初からおすすめを最小化",
 | 
				
			||||||
        "hide_watched": "再生済みの動画をフィードに表示しない",
 | 
					        "hide_watched": "再生済みの動画をフィードに表示しない",
 | 
				
			||||||
        "minimize_chapters_default": "デフォルトでチャプターを最小化する",
 | 
					        "minimize_chapters_default": "最初からチャプターを最小化",
 | 
				
			||||||
        "show_watch_on_youtube": "「YouTubeで見る」ボタンを表示する",
 | 
					        "show_watch_on_youtube": "「YouTubeで見る」ボタンを表示する",
 | 
				
			||||||
        "invalidate_session": "すべてのデバイスでログアウトする",
 | 
					        "invalidate_session": "すべてのデバイスでログアウトする",
 | 
				
			||||||
        "instance_auth_selection": "認証インスタンスの選択",
 | 
					        "instance_auth_selection": "認証インスタンスの選択",
 | 
				
			||||||
| 
						 | 
					@ -119,11 +119,15 @@
 | 
				
			||||||
        "follow_link": "リンクに従う",
 | 
					        "follow_link": "リンクに従う",
 | 
				
			||||||
        "reply_count": "{count} 件の返信",
 | 
					        "reply_count": "{count} 件の返信",
 | 
				
			||||||
        "clone_playlist": "再生リストを複製",
 | 
					        "clone_playlist": "再生リストを複製",
 | 
				
			||||||
        "minimize_comments_default": "デフォルトでコメントを最小化する",
 | 
					        "minimize_comments_default": "最初からコメントを最小化",
 | 
				
			||||||
        "no_valid_playlists": "ファイルに有効な再生リストが含まれていません。",
 | 
					        "no_valid_playlists": "このファイルは有効な再生リストではありません!",
 | 
				
			||||||
        "playlist_bookmarked": "ブックマーク完了",
 | 
					        "playlist_bookmarked": "ブックマーク完了",
 | 
				
			||||||
        "bookmark_playlist": "ブックマーク",
 | 
					        "bookmark_playlist": "ブックマーク",
 | 
				
			||||||
        "with_playlist": "再生リストで共有"
 | 
					        "with_playlist": "再生リストで共有",
 | 
				
			||||||
 | 
					        "skip_automatically": "自動",
 | 
				
			||||||
 | 
					        "skip_button_only": "スキップボタン表示",
 | 
				
			||||||
 | 
					        "skip_segment": "ここをスキップ",
 | 
				
			||||||
 | 
					        "min_segment_length": "最小の区切りの長さ (秒)"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "comment": {
 | 
					    "comment": {
 | 
				
			||||||
        "pinned_by": "{author} によって固定",
 | 
					        "pinned_by": "{author} によって固定",
 | 
				
			||||||
| 
						 | 
					@ -135,8 +139,8 @@
 | 
				
			||||||
        "instance_name": "インスタンス名",
 | 
					        "instance_name": "インスタンス名",
 | 
				
			||||||
        "instance_locations": "インスタンスの場所",
 | 
					        "instance_locations": "インスタンスの場所",
 | 
				
			||||||
        "has_cdn": "CDNの有無",
 | 
					        "has_cdn": "CDNの有無",
 | 
				
			||||||
        "ssl_score": "SSLスコア",
 | 
					        "ssl_score": "SSLの評価",
 | 
				
			||||||
        "registered_users": "登録済みユーザー",
 | 
					        "registered_users": "登録ユーザー数",
 | 
				
			||||||
        "version": "バージョン",
 | 
					        "version": "バージョン",
 | 
				
			||||||
        "up_to_date": "最新?"
 | 
					        "up_to_date": "最新?"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
| 
						 | 
					@ -153,7 +157,8 @@
 | 
				
			||||||
        "chapters": "チャプター",
 | 
					        "chapters": "チャプター",
 | 
				
			||||||
        "live": "{0} ライブ配信",
 | 
					        "live": "{0} ライブ配信",
 | 
				
			||||||
        "shorts": "ショート",
 | 
					        "shorts": "ショート",
 | 
				
			||||||
        "all": "すべて"
 | 
					        "all": "すべて",
 | 
				
			||||||
 | 
					        "category": "分類"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "search": {
 | 
					    "search": {
 | 
				
			||||||
        "did_you_mean": "もしかして: {0}?",
 | 
					        "did_you_mean": "もしかして: {0}?",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -58,15 +58,15 @@
 | 
				
			||||||
        "remove_from_playlist": "Uit Afspeellijst Verwijderen",
 | 
					        "remove_from_playlist": "Uit Afspeellijst Verwijderen",
 | 
				
			||||||
        "select_playlist": "Selecteer een Afspeellijst",
 | 
					        "select_playlist": "Selecteer een Afspeellijst",
 | 
				
			||||||
        "delete_playlist_confirm": "Deze afspeellijst verwijderen?",
 | 
					        "delete_playlist_confirm": "Deze afspeellijst verwijderen?",
 | 
				
			||||||
        "please_select_playlist": "Kies een afspeellijst a.u.b.",
 | 
					        "please_select_playlist": "Selecteer een afspeellijst alsjeblief",
 | 
				
			||||||
        "instance_selection": "Instantie Selectie",
 | 
					        "instance_selection": "Instantie Selectie",
 | 
				
			||||||
        "import_from_json": "Importeren uit JSON/CSV",
 | 
					        "import_from_json": "Importeren uit JSON/CSV",
 | 
				
			||||||
        "clear_history": "Geschiedenis Wissen",
 | 
					        "clear_history": "Geschiedenis Wissen",
 | 
				
			||||||
        "load_more_replies": "Laad meer Antwoorden",
 | 
					        "load_more_replies": "Laad meer Antwoorden",
 | 
				
			||||||
        "delete_playlist_video_confirm": "Video van playlist verwijderen?",
 | 
					        "delete_playlist_video_confirm": "Video uit deze afspeellijst verwijderen?",
 | 
				
			||||||
        "create_playlist": "Afspeellijst Maken",
 | 
					        "create_playlist": "Afspeellijst Maken",
 | 
				
			||||||
        "delete_playlist": "Afspeellijst Verwijderen",
 | 
					        "delete_playlist": "Afspeellijst Verwijderen",
 | 
				
			||||||
        "show_markers": "Toon markeringen op Speler",
 | 
					        "show_markers": "Laat markeringen op speler zien",
 | 
				
			||||||
        "store_search_history": "Zoekgeschiedenis Opslaan",
 | 
					        "store_search_history": "Zoekgeschiedenis Opslaan",
 | 
				
			||||||
        "minimize_chapters_default": "Hoofdstukken Standaard Minimaliseren",
 | 
					        "minimize_chapters_default": "Hoofdstukken Standaard Minimaliseren",
 | 
				
			||||||
        "show_watch_on_youtube": "Toon Bekijk op YouTube knop",
 | 
					        "show_watch_on_youtube": "Toon Bekijk op YouTube knop",
 | 
				
			||||||
| 
						 | 
					@ -77,8 +77,8 @@
 | 
				
			||||||
        "copy_link": "Link kopiëren",
 | 
					        "copy_link": "Link kopiëren",
 | 
				
			||||||
        "hide_watched": "Verberg bekeken video's in de feed",
 | 
					        "hide_watched": "Verberg bekeken video's in de feed",
 | 
				
			||||||
        "minimize_comments": "Opmerkingen minimaliseren",
 | 
					        "minimize_comments": "Opmerkingen minimaliseren",
 | 
				
			||||||
        "instance_auth_selection": "Autenticatie Instantie Selectie",
 | 
					        "instance_auth_selection": "Selectie authenticatie-instantie",
 | 
				
			||||||
        "clone_playlist": "Afspeellijst klonen",
 | 
					        "clone_playlist": "Afspeellijst dupliceren",
 | 
				
			||||||
        "download_as_txt": "Downloaden als .txt",
 | 
					        "download_as_txt": "Downloaden als .txt",
 | 
				
			||||||
        "rename_playlist": "Afspeellijst hernoemen",
 | 
					        "rename_playlist": "Afspeellijst hernoemen",
 | 
				
			||||||
        "new_playlist_name": "Nieuwe afspeellijstnaam",
 | 
					        "new_playlist_name": "Nieuwe afspeellijstnaam",
 | 
				
			||||||
| 
						 | 
					@ -91,20 +91,24 @@
 | 
				
			||||||
        "instance_donations": "Instantie donaties",
 | 
					        "instance_donations": "Instantie donaties",
 | 
				
			||||||
        "reply_count": "{count} antwoorden",
 | 
					        "reply_count": "{count} antwoorden",
 | 
				
			||||||
        "no_valid_playlists": "Het bestand bevat geen geldige afspeellijsten!",
 | 
					        "no_valid_playlists": "Het bestand bevat geen geldige afspeellijsten!",
 | 
				
			||||||
        "clone_playlist_success": "Succesvol gekloond!",
 | 
					        "clone_playlist_success": "Dupliceren gelukt!",
 | 
				
			||||||
        "reset_preferences": "Voorkeuren opnieuw instellen",
 | 
					        "reset_preferences": "Voorkeuren herstellen",
 | 
				
			||||||
        "back_to_home": "Terug naar de start",
 | 
					        "back_to_home": "Terug naar de start",
 | 
				
			||||||
        "minimize_comments_default": "Opmerkingen Standaard Minimaliseren",
 | 
					        "minimize_comments_default": "Opmerkingen Standaard Minimaliseren",
 | 
				
			||||||
        "delete_account": "Account Verwijderen",
 | 
					        "delete_account": "Account Verwijderen",
 | 
				
			||||||
        "logout": "Uitloggen van dit apparaat",
 | 
					        "logout": "Uitloggen op dit apparaat",
 | 
				
			||||||
        "minimize_recommendations_default": "Aanbevelingen Standaard Minimaliseren",
 | 
					        "minimize_recommendations_default": "Aanbevelingen Standaard Minimaliseren",
 | 
				
			||||||
        "confirm_reset_preferences": "Weet u zeker dat u uw voorkeuren opnieuw wilt instellen?",
 | 
					        "confirm_reset_preferences": "Weet u zeker dat u uw voorkeuren opnieuw wilt instellen?",
 | 
				
			||||||
        "backup_preferences": "Back-up voorkeuren",
 | 
					        "backup_preferences": "Back-up voorkeuren",
 | 
				
			||||||
        "invalidate_session": "Alle apparaten afmelden",
 | 
					        "invalidate_session": "Uitloggen op alle apparaten",
 | 
				
			||||||
        "different_auth_instance": "Gebruik een andere instantie voor authenticatie",
 | 
					        "different_auth_instance": "Gebruik een andere instantie voor authenticatie",
 | 
				
			||||||
        "with_playlist": "Delen met afspeellijst",
 | 
					        "with_playlist": "Delen met afspeellijst",
 | 
				
			||||||
        "playlist_bookmarked": "Bladwijzer gemaakt",
 | 
					        "playlist_bookmarked": "Bladwijzer gemaakt",
 | 
				
			||||||
        "bookmark_playlist": "Bladwijzer"
 | 
					        "bookmark_playlist": "Bladwijzer",
 | 
				
			||||||
 | 
					        "skip_automatically": "Automatisch",
 | 
				
			||||||
 | 
					        "skip_button_only": "toon de overslaan knop",
 | 
				
			||||||
 | 
					        "min_segment_length": "Minimale segmentlengte (in seconden)",
 | 
				
			||||||
 | 
					        "skip_segment": "segment overslaan"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "titles": {
 | 
					    "titles": {
 | 
				
			||||||
        "register": "Registreren",
 | 
					        "register": "Registreren",
 | 
				
			||||||
| 
						 | 
					@ -113,9 +117,9 @@
 | 
				
			||||||
        "preferences": "Voorkeuren",
 | 
					        "preferences": "Voorkeuren",
 | 
				
			||||||
        "history": "Geschiedenis",
 | 
					        "history": "Geschiedenis",
 | 
				
			||||||
        "subscriptions": "Abonnementen",
 | 
					        "subscriptions": "Abonnementen",
 | 
				
			||||||
        "trending": "Trending",
 | 
					        "trending": "populair",
 | 
				
			||||||
        "playlists": "Afspeellijsten",
 | 
					        "playlists": "Afspeellijsten",
 | 
				
			||||||
        "account": "Account",
 | 
					        "account": "profiel",
 | 
				
			||||||
        "instance": "Instantie",
 | 
					        "instance": "Instantie",
 | 
				
			||||||
        "player": "Speler",
 | 
					        "player": "Speler",
 | 
				
			||||||
        "livestreams": "Livestreams",
 | 
					        "livestreams": "Livestreams",
 | 
				
			||||||
| 
						 | 
					@ -148,7 +152,9 @@
 | 
				
			||||||
        "sponsor_segments": "Sponsorsegmenten",
 | 
					        "sponsor_segments": "Sponsorsegmenten",
 | 
				
			||||||
        "ratings_disabled": "Beoordelingen Uitgeschakeld",
 | 
					        "ratings_disabled": "Beoordelingen Uitgeschakeld",
 | 
				
			||||||
        "live": "{0} Live",
 | 
					        "live": "{0} Live",
 | 
				
			||||||
        "shorts": "Shorts"
 | 
					        "shorts": "Shorts",
 | 
				
			||||||
 | 
					        "category": "Categorie",
 | 
				
			||||||
 | 
					        "all": "Alle"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "preferences": {
 | 
					    "preferences": {
 | 
				
			||||||
        "has_cdn": "Heeft CDN?",
 | 
					        "has_cdn": "Heeft CDN?",
 | 
				
			||||||
| 
						 | 
					@ -161,8 +167,8 @@
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "comment": {
 | 
					    "comment": {
 | 
				
			||||||
        "pinned_by": "Vastgemaakt door {author}",
 | 
					        "pinned_by": "Vastgemaakt door {author}",
 | 
				
			||||||
        "user_disabled": "Reacties zijn uitgeschakeld in de instellingen.",
 | 
					        "user_disabled": "Opmerkingen zijn uitgeschakeld in de instellingen.",
 | 
				
			||||||
        "loading": "Reacties laden...",
 | 
					        "loading": "Opmerkingen laden...",
 | 
				
			||||||
        "disabled": "Reacties zijn uitgeschakeld door de uploader."
 | 
					        "disabled": "Reacties zijn uitgeschakeld door de uploader."
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "info": {
 | 
					    "info": {
 | 
				
			||||||
| 
						 | 
					@ -170,7 +176,8 @@
 | 
				
			||||||
        "copied": "Gekopieerd!",
 | 
					        "copied": "Gekopieerd!",
 | 
				
			||||||
        "cannot_copy": "Kan niet kopiëren!",
 | 
					        "cannot_copy": "Kan niet kopiëren!",
 | 
				
			||||||
        "page_not_found": "Pagina niet gevonden",
 | 
					        "page_not_found": "Pagina niet gevonden",
 | 
				
			||||||
        "local_storage": "Deze actie vereist lokale opslag, zijn cookies ingeschakeld?"
 | 
					        "local_storage": "Deze actie vereist lokale opslag, zijn cookies ingeschakeld?",
 | 
				
			||||||
 | 
					        "register_no_email_note": "Een e-mailadres als gebruikersnaam gebruiken wordt afgeraden. Toch doorgaan?"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "subscriptions": {
 | 
					    "subscriptions": {
 | 
				
			||||||
        "subscribed_channels_count": "Geabonneerd op: {0}"
 | 
					        "subscribed_channels_count": "Geabonneerd op: {0}"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -144,7 +144,8 @@
 | 
				
			||||||
        "ratings_disabled": "ମୂଲ୍ୟାୟନ ଅକ୍ଷମ ହୋଇଛି",
 | 
					        "ratings_disabled": "ମୂଲ୍ୟାୟନ ଅକ୍ଷମ ହୋଇଛି",
 | 
				
			||||||
        "chapters": "ଅଧ୍ୟାୟ ଗୁଡ଼ିକ",
 | 
					        "chapters": "ଅଧ୍ୟାୟ ଗୁଡ଼ିକ",
 | 
				
			||||||
        "live": "{0} ସିଧାପ୍ରସାରଣ",
 | 
					        "live": "{0} ସିଧାପ୍ରସାରଣ",
 | 
				
			||||||
        "all": "ସମସ୍ତ"
 | 
					        "all": "ସମସ୍ତ",
 | 
				
			||||||
 | 
					        "category": "ବର୍ଗ"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "search": {
 | 
					    "search": {
 | 
				
			||||||
        "did_you_mean": "ଆପଣ କହିବାକୁ ଚାହୁଁଛନ୍ତି କି: {0}?",
 | 
					        "did_you_mean": "ଆପଣ କହିବାକୁ ଚାହୁଁଛନ୍ତି କି: {0}?",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -157,7 +157,8 @@
 | 
				
			||||||
        "chapters": "Rozdziały",
 | 
					        "chapters": "Rozdziały",
 | 
				
			||||||
        "live": "{0} Na żywo",
 | 
					        "live": "{0} Na żywo",
 | 
				
			||||||
        "shorts": "Krótkie wideo",
 | 
					        "shorts": "Krótkie wideo",
 | 
				
			||||||
        "all": "Wszystkie"
 | 
					        "all": "Wszystkie",
 | 
				
			||||||
 | 
					        "category": "Kategoria"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "search": {
 | 
					    "search": {
 | 
				
			||||||
        "did_you_mean": "Czy chodziło ci o: {0}?",
 | 
					        "did_you_mean": "Czy chodziło ci o: {0}?",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -100,7 +100,15 @@
 | 
				
			||||||
        "minimize_recommendations": "Ascunde Recomandări",
 | 
					        "minimize_recommendations": "Ascunde Recomandări",
 | 
				
			||||||
        "yes": "Da",
 | 
					        "yes": "Da",
 | 
				
			||||||
        "show_comments": "Arată Comentarii",
 | 
					        "show_comments": "Arată Comentarii",
 | 
				
			||||||
        "show_description": "Arată Descriere"
 | 
					        "show_description": "Arată Descriere",
 | 
				
			||||||
 | 
					        "bookmark_playlist": "Marcaj",
 | 
				
			||||||
 | 
					        "no_valid_playlists": "Fișierul nu conține playlist-uri valide!",
 | 
				
			||||||
 | 
					        "skip_automatically": "Automat",
 | 
				
			||||||
 | 
					        "min_segment_length": "Lungimea minimă a segmentului (în secunde)",
 | 
				
			||||||
 | 
					        "skip_segment": "Sări segmentul",
 | 
				
			||||||
 | 
					        "skip_button_only": "Afișează butonul de săritură",
 | 
				
			||||||
 | 
					        "with_playlist": "Distribuie cu playlist",
 | 
				
			||||||
 | 
					        "playlist_bookmarked": "Marcat"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "preferences": {
 | 
					    "preferences": {
 | 
				
			||||||
        "ssl_score": "Scor SSL",
 | 
					        "ssl_score": "Scor SSL",
 | 
				
			||||||
| 
						 | 
					@ -125,7 +133,9 @@
 | 
				
			||||||
        "sponsor_segments": "Segmente Sponsori",
 | 
					        "sponsor_segments": "Segmente Sponsori",
 | 
				
			||||||
        "ratings_disabled": "Like-uri dezactivate",
 | 
					        "ratings_disabled": "Like-uri dezactivate",
 | 
				
			||||||
        "live": "{0} Live",
 | 
					        "live": "{0} Live",
 | 
				
			||||||
        "videos": "Video-uri"
 | 
					        "videos": "Video-uri",
 | 
				
			||||||
 | 
					        "category": "Categorie",
 | 
				
			||||||
 | 
					        "all": "Tot"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "login": {
 | 
					    "login": {
 | 
				
			||||||
        "username": "Nume User",
 | 
					        "username": "Nume User",
 | 
				
			||||||
| 
						 | 
					@ -146,7 +156,9 @@
 | 
				
			||||||
        "cannot_copy": "Nu se poate copia!",
 | 
					        "cannot_copy": "Nu se poate copia!",
 | 
				
			||||||
        "preferences_note": "Sfat: preferințele sunt salvate in memoria locala a browserului tău. Ștergând datele browserului le ștergi si pe ele.",
 | 
					        "preferences_note": "Sfat: preferințele sunt salvate in memoria locala a browserului tău. Ștergând datele browserului le ștergi si pe ele.",
 | 
				
			||||||
        "page_not_found": "Pagină negăsită",
 | 
					        "page_not_found": "Pagină negăsită",
 | 
				
			||||||
        "copied": "S-a copiat!"
 | 
					        "copied": "S-a copiat!",
 | 
				
			||||||
 | 
					        "register_no_email_note": "Utilizarea unui e-mail ca nume de utilizator nu este recomandată. Continui oricum?",
 | 
				
			||||||
 | 
					        "local_storage": "Această acțiune necesită localStorage, sunt activate cookie-urile?"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "subscriptions": {
 | 
					    "subscriptions": {
 | 
				
			||||||
        "subscribed_channels_count": "Abonat la: {0}"
 | 
					        "subscribed_channels_count": "Abonat la: {0}"
 | 
				
			||||||
| 
						 | 
					@ -164,7 +176,8 @@
 | 
				
			||||||
        "livestreams": "Live-uri",
 | 
					        "livestreams": "Live-uri",
 | 
				
			||||||
        "channels": "Canale",
 | 
					        "channels": "Canale",
 | 
				
			||||||
        "preferences": "Preferințe",
 | 
					        "preferences": "Preferințe",
 | 
				
			||||||
        "player": "Player"
 | 
					        "player": "Player",
 | 
				
			||||||
 | 
					        "bookmarks": "Marcaje"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "player": {
 | 
					    "player": {
 | 
				
			||||||
        "watch_on": "Vezi pe {0}"
 | 
					        "watch_on": "Vezi pe {0}"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,8 +5,8 @@
 | 
				
			||||||
        "register": "Регистрация",
 | 
					        "register": "Регистрация",
 | 
				
			||||||
        "feed": "Подписки",
 | 
					        "feed": "Подписки",
 | 
				
			||||||
        "preferences": "Настройки",
 | 
					        "preferences": "Настройки",
 | 
				
			||||||
        "history": "История просмотров",
 | 
					        "history": "История",
 | 
				
			||||||
        "subscriptions": "Ваши подписки",
 | 
					        "subscriptions": "Подписки",
 | 
				
			||||||
        "playlists": "Плейлисты",
 | 
					        "playlists": "Плейлисты",
 | 
				
			||||||
        "account": "Аккаунт",
 | 
					        "account": "Аккаунт",
 | 
				
			||||||
        "player": "Плеер",
 | 
					        "player": "Плеер",
 | 
				
			||||||
| 
						 | 
					@ -28,7 +28,7 @@
 | 
				
			||||||
        "channel_name_asc": "Имя канала (А-Я)",
 | 
					        "channel_name_asc": "Имя канала (А-Я)",
 | 
				
			||||||
        "channel_name_desc": "Имя канала (Я-А)",
 | 
					        "channel_name_desc": "Имя канала (Я-А)",
 | 
				
			||||||
        "back": "Назад",
 | 
					        "back": "Назад",
 | 
				
			||||||
        "uses_api_from": "Использовать API, предоставляемое ",
 | 
					        "uses_api_from": "Использовать API ",
 | 
				
			||||||
        "enable_sponsorblock": "Включить Sponsorblock",
 | 
					        "enable_sponsorblock": "Включить Sponsorblock",
 | 
				
			||||||
        "skip_sponsors": "Пропускать спонсорскую рекламу",
 | 
					        "skip_sponsors": "Пропускать спонсорскую рекламу",
 | 
				
			||||||
        "skip_intro": "Пропускать заставку/интро",
 | 
					        "skip_intro": "Пропускать заставку/интро",
 | 
				
			||||||
| 
						 | 
					@ -67,7 +67,7 @@
 | 
				
			||||||
        "minimize_recommendations": "Свернуть рекомендации",
 | 
					        "minimize_recommendations": "Свернуть рекомендации",
 | 
				
			||||||
        "show_recommendations": "Показать рекомендации",
 | 
					        "show_recommendations": "Показать рекомендации",
 | 
				
			||||||
        "disable_lbry": "Отключить LBRY для стриминга",
 | 
					        "disable_lbry": "Отключить LBRY для стриминга",
 | 
				
			||||||
        "enable_lbry_proxy": "Проксировать видео с LBRY",
 | 
					        "enable_lbry_proxy": "Проксировать видео для LBRY",
 | 
				
			||||||
        "view_ssl_score": "Посмотреть настройки SSL",
 | 
					        "view_ssl_score": "Посмотреть настройки SSL",
 | 
				
			||||||
        "search": "Поиск",
 | 
					        "search": "Поиск",
 | 
				
			||||||
        "filter": "Фильтр",
 | 
					        "filter": "Фильтр",
 | 
				
			||||||
| 
						 | 
					@ -85,42 +85,42 @@
 | 
				
			||||||
        "select_playlist": "Выбрать плейлист",
 | 
					        "select_playlist": "Выбрать плейлист",
 | 
				
			||||||
        "delete_playlist_confirm": "Удалить этот плейлист?",
 | 
					        "delete_playlist_confirm": "Удалить этот плейлист?",
 | 
				
			||||||
        "delete_playlist_video_confirm": "Удалить видео из плейлиста?",
 | 
					        "delete_playlist_video_confirm": "Удалить видео из плейлиста?",
 | 
				
			||||||
        "show_markers": "Показать Mаркеры Hа Проигрывателе",
 | 
					        "show_markers": "Показать маркеры на проигрывателе",
 | 
				
			||||||
        "delete_account": "Удалить аккаунт",
 | 
					        "delete_account": "Удалить аккаунт",
 | 
				
			||||||
        "logout": "Выйти из этого устройства",
 | 
					        "logout": "Выйти из этого устройства",
 | 
				
			||||||
        "download_as_txt": "Скачать как .txt",
 | 
					        "download_as_txt": "Скачать как .txt",
 | 
				
			||||||
        "minimize_recommendations_default": "Скрыть Рекомендации по умолчанию",
 | 
					        "minimize_recommendations_default": "Скрыть Рекомендации по умолчанию",
 | 
				
			||||||
        "invalidate_session": "Выйти из всех устройств",
 | 
					        "invalidate_session": "Выйти из всех устройств",
 | 
				
			||||||
        "different_auth_instance": "Использовать другие средства аутентификации",
 | 
					        "different_auth_instance": "Использовать другое зеркало для аутентификации",
 | 
				
			||||||
        "instance_auth_selection": "Выбор средств аутентификации",
 | 
					        "instance_auth_selection": "Выбор зеркала аутентификации",
 | 
				
			||||||
        "clone_playlist": "Клонировать плейлист",
 | 
					        "clone_playlist": "Клонировать плейлист",
 | 
				
			||||||
        "clone_playlist_success": "Клонирование прошло успешно!",
 | 
					        "clone_playlist_success": "Успешно клонировано!",
 | 
				
			||||||
        "show_chapters": "Части",
 | 
					        "show_chapters": "Главы",
 | 
				
			||||||
        "rename_playlist": "Переименовать плейлист",
 | 
					        "rename_playlist": "Переименовать плейлист",
 | 
				
			||||||
        "new_playlist_name": "Новое название плейлиста",
 | 
					        "new_playlist_name": "Новое название плейлиста",
 | 
				
			||||||
        "share": "Поделиться",
 | 
					        "share": "Поделиться",
 | 
				
			||||||
        "with_timecode": "Поделиться с отметкой времени",
 | 
					        "with_timecode": "Поделиться с таймкодом",
 | 
				
			||||||
        "piped_link": "Ссылка Piped",
 | 
					        "piped_link": "Ссылка Piped",
 | 
				
			||||||
        "follow_link": "Ссылка подписки",
 | 
					        "follow_link": "Перейти по ссылке",
 | 
				
			||||||
        "copy_link": "Скопировать ссылку",
 | 
					        "copy_link": "Скопировать ссылку",
 | 
				
			||||||
        "time_code": "Тайм-код (в секундах)",
 | 
					        "time_code": "Таймкод (в секундах)",
 | 
				
			||||||
        "reset_preferences": "Сбросить настройки",
 | 
					        "reset_preferences": "Сбросить настройки",
 | 
				
			||||||
        "confirm_reset_preferences": "Вы уверены, что хотите сбросить настройки?",
 | 
					        "confirm_reset_preferences": "Вы уверены, что хотите сбросить настройки?",
 | 
				
			||||||
        "backup_preferences": "Бэкап настроек",
 | 
					        "backup_preferences": "Бэкап настроек",
 | 
				
			||||||
        "restore_preferences": "Восстановить настройки",
 | 
					        "restore_preferences": "Восстановить настройки",
 | 
				
			||||||
        "back_to_home": "Вернутся на главную",
 | 
					        "back_to_home": "Назад на главную",
 | 
				
			||||||
        "store_search_history": "Хранить историю поиска",
 | 
					        "store_search_history": "Хранить историю поиска",
 | 
				
			||||||
        "hide_watched": "Скрыть просмотренные видео в ленте",
 | 
					        "hide_watched": "Скрыть просмотренные видео в ленте",
 | 
				
			||||||
        "status_page": "Статус",
 | 
					        "status_page": "Статус",
 | 
				
			||||||
        "source_code": "Исходный код",
 | 
					        "source_code": "Исходный код",
 | 
				
			||||||
        "documentation": "Пожертвования сервера",
 | 
					        "documentation": "Документация",
 | 
				
			||||||
        "instance_donations": "Пожертвования сервера",
 | 
					        "instance_donations": "Пожертвования зеркала",
 | 
				
			||||||
        "reply_count": "{count} ответов",
 | 
					        "reply_count": "{count} ответов",
 | 
				
			||||||
        "minimize_comments_default": "Сворачивать комментарии по умолчанию",
 | 
					        "minimize_comments_default": "Сворачивать комментарии по умолчанию",
 | 
				
			||||||
        "minimize_comments": "Свернуть комментарии",
 | 
					        "minimize_comments": "Свернуть комментарии",
 | 
				
			||||||
        "show_watch_on_youtube": "Показать кнопку Смотреть на YouTube",
 | 
					        "show_watch_on_youtube": "Показать кнопку Смотреть на YouTube",
 | 
				
			||||||
        "minimize_chapters_default": "Скрывать главы по умолчанию",
 | 
					        "minimize_chapters_default": "Скрывать главы по умолчанию",
 | 
				
			||||||
        "no_valid_playlists": "Файл не содержит действительных списков воспроизведения!",
 | 
					        "no_valid_playlists": "Файл не содержит действующих плейлистов!",
 | 
				
			||||||
        "with_playlist": "Поделиться с плейлистом",
 | 
					        "with_playlist": "Поделиться с плейлистом",
 | 
				
			||||||
        "bookmark_playlist": "Закладка",
 | 
					        "bookmark_playlist": "Закладка",
 | 
				
			||||||
        "playlist_bookmarked": "В закладках",
 | 
					        "playlist_bookmarked": "В закладках",
 | 
				
			||||||
| 
						 | 
					@ -130,14 +130,14 @@
 | 
				
			||||||
        "skip_segment": "Пропустить сегмент"
 | 
					        "skip_segment": "Пропустить сегмент"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "comment": {
 | 
					    "comment": {
 | 
				
			||||||
        "pinned_by": "Прикреплено пользователем {author}",
 | 
					        "pinned_by": "Закреплено пользователем {author}",
 | 
				
			||||||
        "loading": "Загрузка комментариев...",
 | 
					        "loading": "Загрузка комментариев...",
 | 
				
			||||||
        "user_disabled": "Комментарии отключены в настройках.",
 | 
					        "user_disabled": "Комментарии отключены в настройках.",
 | 
				
			||||||
        "disabled": "Коментарии отключены автором."
 | 
					        "disabled": "Комментарии отключены автором."
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "preferences": {
 | 
					    "preferences": {
 | 
				
			||||||
        "instance_name": "Название",
 | 
					        "instance_name": "Имя зеркала",
 | 
				
			||||||
        "instance_locations": "Местоположение",
 | 
					        "instance_locations": "Местоположения зеркала",
 | 
				
			||||||
        "has_cdn": "Имеется CDN?",
 | 
					        "has_cdn": "Имеется CDN?",
 | 
				
			||||||
        "ssl_score": "Оценка настроек SSL",
 | 
					        "ssl_score": "Оценка настроек SSL",
 | 
				
			||||||
        "registered_users": "Зарегистрировано пользователей",
 | 
					        "registered_users": "Зарегистрировано пользователей",
 | 
				
			||||||
| 
						 | 
					@ -145,7 +145,7 @@
 | 
				
			||||||
        "up_to_date": "Версия актуальна?"
 | 
					        "up_to_date": "Версия актуальна?"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "login": {
 | 
					    "login": {
 | 
				
			||||||
        "username": "Аккаунт на Piped",
 | 
					        "username": "Имя пользователя",
 | 
				
			||||||
        "password": "Пароль"
 | 
					        "password": "Пароль"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "video": {
 | 
					    "video": {
 | 
				
			||||||
| 
						 | 
					@ -157,7 +157,8 @@
 | 
				
			||||||
        "live": "{0} В эфире",
 | 
					        "live": "{0} В эфире",
 | 
				
			||||||
        "chapters": "Содержание",
 | 
					        "chapters": "Содержание",
 | 
				
			||||||
        "shorts": "Shorts",
 | 
					        "shorts": "Shorts",
 | 
				
			||||||
        "all": "Все"
 | 
					        "all": "Все",
 | 
				
			||||||
 | 
					        "category": "Категория"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "search": {
 | 
					    "search": {
 | 
				
			||||||
        "did_you_mean": "Может быть вы имели в виду: {0}?",
 | 
					        "did_you_mean": "Может быть вы имели в виду: {0}?",
 | 
				
			||||||
| 
						 | 
					@ -174,11 +175,11 @@
 | 
				
			||||||
        "subscribed_channels_count": "Подписан на: {0}"
 | 
					        "subscribed_channels_count": "Подписан на: {0}"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "info": {
 | 
					    "info": {
 | 
				
			||||||
        "preferences_note": "Примечание: настройки сохранены в локальном хранилище браузера. При удалении данных браузера они будут удалены.",
 | 
					        "preferences_note": "Примечание: настройки сохранены в локальном хранилище браузера. Удаление данных вашего браузера сбросит их.",
 | 
				
			||||||
        "copied": "Скопировано!",
 | 
					        "copied": "Скопировано!",
 | 
				
			||||||
        "cannot_copy": "Не получилось скопировать!",
 | 
					        "cannot_copy": "Не удалось скопировать!",
 | 
				
			||||||
        "page_not_found": "Страница не найдена",
 | 
					        "page_not_found": "Страница не найдена",
 | 
				
			||||||
        "local_storage": "Это действие требует локального хранилища (localStorage), разрешены ли файлы cookie?",
 | 
					        "local_storage": "Это действие требует разрешения localStorage, включены ли cookie-файлы?",
 | 
				
			||||||
        "register_no_email_note": "Использование электронной почты в качестве имени пользователя не рекомендуется. Продолжить?"
 | 
					        "register_no_email_note": "Использование электронной почты в качестве имени пользователя не рекомендуется. Продолжить?"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -157,7 +157,8 @@
 | 
				
			||||||
        "shorts": "කෙටි වීඩියෝ",
 | 
					        "shorts": "කෙටි වීඩියෝ",
 | 
				
			||||||
        "ratings_disabled": "ශ්රේණිගත කිරීම් අබල කර ඇත",
 | 
					        "ratings_disabled": "ශ්රේණිගත කිරීම් අබල කර ඇත",
 | 
				
			||||||
        "live": "{0} සජීවී",
 | 
					        "live": "{0} සජීවී",
 | 
				
			||||||
        "all": "සියල්ල"
 | 
					        "all": "සියල්ල",
 | 
				
			||||||
 | 
					        "category": "කාණ්ඩය"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "search": {
 | 
					    "search": {
 | 
				
			||||||
        "did_you_mean": "ඔබ අදහස් කළේ: {0}?",
 | 
					        "did_you_mean": "ඔබ අදහස් කළේ: {0}?",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -45,7 +45,7 @@
 | 
				
			||||||
        "export_to_json": "JSON Olarak Dışa Aktar",
 | 
					        "export_to_json": "JSON Olarak Dışa Aktar",
 | 
				
			||||||
        "no": "Hayır",
 | 
					        "no": "Hayır",
 | 
				
			||||||
        "yes": "Evet",
 | 
					        "yes": "Evet",
 | 
				
			||||||
        "show_more": "Daha Fazla Göster",
 | 
					        "show_more": "Daha fazla göster",
 | 
				
			||||||
        "instance_selection": "Örnek Seçimi",
 | 
					        "instance_selection": "Örnek Seçimi",
 | 
				
			||||||
        "loading": "Yükleniyor...",
 | 
					        "loading": "Yükleniyor...",
 | 
				
			||||||
        "filter": "Filtrele",
 | 
					        "filter": "Filtrele",
 | 
				
			||||||
| 
						 | 
					@ -108,7 +108,8 @@
 | 
				
			||||||
        "min_segment_length": "En Küçük Bölüm Uzunluğu (saniye cinsinden)",
 | 
					        "min_segment_length": "En Küçük Bölüm Uzunluğu (saniye cinsinden)",
 | 
				
			||||||
        "skip_segment": "Bölümü Atla",
 | 
					        "skip_segment": "Bölümü Atla",
 | 
				
			||||||
        "skip_button_only": "Atla düğmesini göster",
 | 
					        "skip_button_only": "Atla düğmesini göster",
 | 
				
			||||||
        "skip_automatically": "Otomatik olarak"
 | 
					        "skip_automatically": "Otomatik olarak",
 | 
				
			||||||
 | 
					        "show_less": "Daha az göster"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "player": {
 | 
					    "player": {
 | 
				
			||||||
        "watch_on": "{0} Üzerinde İzle"
 | 
					        "watch_on": "{0} Üzerinde İzle"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,7 +28,7 @@
 | 
				
			||||||
        "show_comments": "Hiển thị bình luận",
 | 
					        "show_comments": "Hiển thị bình luận",
 | 
				
			||||||
        "store_watch_history": "Lịch sử xem trên cửa hàng",
 | 
					        "store_watch_history": "Lịch sử xem trên cửa hàng",
 | 
				
			||||||
        "language_selection": "Lựa chọn ngôn ngữ",
 | 
					        "language_selection": "Lựa chọn ngôn ngữ",
 | 
				
			||||||
        "instances_list": "Danh sách phiên bản",
 | 
					        "instances_list": "Danh sách instance",
 | 
				
			||||||
        "show_more": "Hiện thị nhiều hơn",
 | 
					        "show_more": "Hiện thị nhiều hơn",
 | 
				
			||||||
        "import_from_json": "Nhập từ JSON/CSV",
 | 
					        "import_from_json": "Nhập từ JSON/CSV",
 | 
				
			||||||
        "loop_this_video": "Lặp lại video này",
 | 
					        "loop_this_video": "Lặp lại video này",
 | 
				
			||||||
| 
						 | 
					@ -53,7 +53,7 @@
 | 
				
			||||||
        "light": "Sáng",
 | 
					        "light": "Sáng",
 | 
				
			||||||
        "audio_only": "Chỉ có âm thanh",
 | 
					        "audio_only": "Chỉ có âm thanh",
 | 
				
			||||||
        "minimize_description_default": "Thu nhỏ mô tả theo mặc định",
 | 
					        "minimize_description_default": "Thu nhỏ mô tả theo mặc định",
 | 
				
			||||||
        "instance_selection": "Lựa chọn phiên bản",
 | 
					        "instance_selection": "Lựa chọn instance",
 | 
				
			||||||
        "yes": "Có",
 | 
					        "yes": "Có",
 | 
				
			||||||
        "enabled_codecs": "Các codec được bật (Nhiều)",
 | 
					        "enabled_codecs": "Các codec được bật (Nhiều)",
 | 
				
			||||||
        "export_to_json": "Xuất định dạng JSON",
 | 
					        "export_to_json": "Xuất định dạng JSON",
 | 
				
			||||||
| 
						 | 
					@ -78,7 +78,8 @@
 | 
				
			||||||
        "minimize_comments": "Thu nhỏ bình luận",
 | 
					        "minimize_comments": "Thu nhỏ bình luận",
 | 
				
			||||||
        "reply_count": "{count} phản hồi",
 | 
					        "reply_count": "{count} phản hồi",
 | 
				
			||||||
        "status_page": "Trạng thái",
 | 
					        "status_page": "Trạng thái",
 | 
				
			||||||
        "new_playlist_name": "Tên danh sách phát mới"
 | 
					        "new_playlist_name": "Tên danh sách phát mới",
 | 
				
			||||||
 | 
					        "skip_automatically": "Tự động"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "titles": {
 | 
					    "titles": {
 | 
				
			||||||
        "register": "Đăng ký",
 | 
					        "register": "Đăng ký",
 | 
				
			||||||
| 
						 | 
					@ -92,7 +93,8 @@
 | 
				
			||||||
        "account": "Tài khoản",
 | 
					        "account": "Tài khoản",
 | 
				
			||||||
        "channels": "Kênh",
 | 
					        "channels": "Kênh",
 | 
				
			||||||
        "instance": "Instance",
 | 
					        "instance": "Instance",
 | 
				
			||||||
        "player": "Trình phát video"
 | 
					        "player": "Trình phát video",
 | 
				
			||||||
 | 
					        "livestreams": "Phát sóng trực tiếp"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "player": {
 | 
					    "player": {
 | 
				
			||||||
        "watch_on": "Xem trên {0}"
 | 
					        "watch_on": "Xem trên {0}"
 | 
				
			||||||
| 
						 | 
					@ -104,8 +106,8 @@
 | 
				
			||||||
        "disabled": "Bình luận đã bị tắt bởi người đăng video."
 | 
					        "disabled": "Bình luận đã bị tắt bởi người đăng video."
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "preferences": {
 | 
					    "preferences": {
 | 
				
			||||||
        "instance_name": "Tên phiên bản",
 | 
					        "instance_name": "Tên instance",
 | 
				
			||||||
        "instance_locations": "Vị trí phiên bản",
 | 
					        "instance_locations": "Vị trí instance",
 | 
				
			||||||
        "has_cdn": "Có CDN?",
 | 
					        "has_cdn": "Có CDN?",
 | 
				
			||||||
        "registered_users": "Người dùng đã đăng ký",
 | 
					        "registered_users": "Người dùng đã đăng ký",
 | 
				
			||||||
        "version": "Phiên bản",
 | 
					        "version": "Phiên bản",
 | 
				
			||||||
| 
						 | 
					@ -124,7 +126,8 @@
 | 
				
			||||||
        "live": "{0} Trực tiếp",
 | 
					        "live": "{0} Trực tiếp",
 | 
				
			||||||
        "chapters": "Chương",
 | 
					        "chapters": "Chương",
 | 
				
			||||||
        "videos": "Video",
 | 
					        "videos": "Video",
 | 
				
			||||||
        "shorts": "Shorts"
 | 
					        "shorts": "Shorts",
 | 
				
			||||||
 | 
					        "all": "Tất cả"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "search": {
 | 
					    "search": {
 | 
				
			||||||
        "did_you_mean": "Ý của bạn là: {0}?",
 | 
					        "did_you_mean": "Ý của bạn là: {0}?",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -44,7 +44,7 @@
 | 
				
			||||||
        "least_recent": "最早的",
 | 
					        "least_recent": "最早的",
 | 
				
			||||||
        "most_recent": "最新的",
 | 
					        "most_recent": "最新的",
 | 
				
			||||||
        "sort_by": "排序:",
 | 
					        "sort_by": "排序:",
 | 
				
			||||||
        "view_subscriptions": "查看订阅",
 | 
					        "view_subscriptions": "查看订阅列表",
 | 
				
			||||||
        "unsubscribe": "取消订阅 - {count}",
 | 
					        "unsubscribe": "取消订阅 - {count}",
 | 
				
			||||||
        "subscribe": "订阅 - {count}",
 | 
					        "subscribe": "订阅 - {count}",
 | 
				
			||||||
        "loading": "正在加载...",
 | 
					        "loading": "正在加载...",
 | 
				
			||||||
| 
						 | 
					@ -108,7 +108,8 @@
 | 
				
			||||||
        "skip_automatically": "自动",
 | 
					        "skip_automatically": "自动",
 | 
				
			||||||
        "min_segment_length": "最小分段长度(以秒为单位)",
 | 
					        "min_segment_length": "最小分段长度(以秒为单位)",
 | 
				
			||||||
        "skip_segment": "跳过分段",
 | 
					        "skip_segment": "跳过分段",
 | 
				
			||||||
        "skip_button_only": "显示跳过按钮"
 | 
					        "skip_button_only": "显示跳过按钮",
 | 
				
			||||||
 | 
					        "show_less": "显示更少"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "video": {
 | 
					    "video": {
 | 
				
			||||||
        "sponsor_segments": "赞助商部分",
 | 
					        "sponsor_segments": "赞助商部分",
 | 
				
			||||||
| 
						 | 
					@ -141,8 +142,8 @@
 | 
				
			||||||
        "watch_on": "在 {0} 观看"
 | 
					        "watch_on": "在 {0} 观看"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "titles": {
 | 
					    "titles": {
 | 
				
			||||||
        "feed": "RSS 订阅源",
 | 
					        "feed": "订阅流",
 | 
				
			||||||
        "subscriptions": "订阅",
 | 
					        "subscriptions": "订阅列表",
 | 
				
			||||||
        "history": "历史",
 | 
					        "history": "历史",
 | 
				
			||||||
        "preferences": "设置",
 | 
					        "preferences": "设置",
 | 
				
			||||||
        "register": "注册",
 | 
					        "register": "注册",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,7 +27,7 @@ const routes = [
 | 
				
			||||||
        component: () => import("../components/PlaylistPage.vue"),
 | 
					        component: () => import("../components/PlaylistPage.vue"),
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        path: "/:path(v|w|embed|shorts|watch)/:v?",
 | 
					        path: "/:path(v|w|embed|live|shorts|watch)/:v?",
 | 
				
			||||||
        name: "WatchVideo",
 | 
					        name: "WatchVideo",
 | 
				
			||||||
        component: () => import("../components/WatchVideo.vue"),
 | 
					        component: () => import("../components/WatchVideo.vue"),
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
| 
						 | 
					@ -41,6 +41,11 @@ const routes = [
 | 
				
			||||||
        name: "Channel",
 | 
					        name: "Channel",
 | 
				
			||||||
        component: () => import("../components/ChannelPage.vue"),
 | 
					        component: () => import("../components/ChannelPage.vue"),
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        path: "/@:channelId",
 | 
				
			||||||
 | 
					        name: "Channel handle",
 | 
				
			||||||
 | 
					        component: () => import("../components/ChannelPage.vue"),
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        path: "/login",
 | 
					        path: "/login",
 | 
				
			||||||
        name: "Login",
 | 
					        name: "Login",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,12 +4,12 @@ import { Buffer } from "buffer";
 | 
				
			||||||
window.Buffer = Buffer;
 | 
					window.Buffer = Buffer;
 | 
				
			||||||
import { json2xml } from "xml-js";
 | 
					import { json2xml } from "xml-js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const DashUtils = {
 | 
					export function generate_dash_file_from_formats(VideoFormats, VideoLength) {
 | 
				
			||||||
    generate_dash_file_from_formats(VideoFormats, VideoLength) {
 | 
					    const generatedJSON = generate_xmljs_json_from_data(VideoFormats, VideoLength);
 | 
				
			||||||
        const generatedJSON = this.generate_xmljs_json_from_data(VideoFormats, VideoLength);
 | 
					 | 
				
			||||||
    return json2xml(generatedJSON);
 | 
					    return json2xml(generatedJSON);
 | 
				
			||||||
    },
 | 
					}
 | 
				
			||||||
    generate_xmljs_json_from_data(VideoFormatArray, VideoLength) {
 | 
					
 | 
				
			||||||
 | 
					function generate_xmljs_json_from_data(VideoFormatArray, VideoLength) {
 | 
				
			||||||
    const convertJSON = {
 | 
					    const convertJSON = {
 | 
				
			||||||
        declaration: {
 | 
					        declaration: {
 | 
				
			||||||
            attributes: {
 | 
					            attributes: {
 | 
				
			||||||
| 
						 | 
					@ -32,22 +32,26 @@ const DashUtils = {
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        type: "element",
 | 
					                        type: "element",
 | 
				
			||||||
                        name: "Period",
 | 
					                        name: "Period",
 | 
				
			||||||
                            elements: this.generate_adaptation_set(VideoFormatArray),
 | 
					                        elements: generate_adaptation_set(VideoFormatArray),
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    return convertJSON;
 | 
					    return convertJSON;
 | 
				
			||||||
    },
 | 
					}
 | 
				
			||||||
    generate_adaptation_set(VideoFormatArray) {
 | 
					
 | 
				
			||||||
 | 
					function generate_adaptation_set(VideoFormatArray) {
 | 
				
			||||||
    const adaptationSets = [];
 | 
					    const adaptationSets = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mimeAudioObjs = [];
 | 
					    let mimeAudioObjs = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    VideoFormatArray.forEach(videoFormat => {
 | 
					    VideoFormatArray.forEach(videoFormat => {
 | 
				
			||||||
        // the dual formats should not be used
 | 
					        // the dual formats should not be used
 | 
				
			||||||
            if (videoFormat.mimeType.indexOf("video") != -1 && !videoFormat.videoOnly) {
 | 
					        if (
 | 
				
			||||||
 | 
					            (videoFormat.mimeType.includes("video") && !videoFormat.videoOnly) ||
 | 
				
			||||||
 | 
					            videoFormat.mimeType.includes("application")
 | 
				
			||||||
 | 
					        ) {
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -97,17 +101,18 @@ const DashUtils = {
 | 
				
			||||||
        for (var i = 0; i < mimeAudioObj.videoFormats.length; i++) {
 | 
					        for (var i = 0; i < mimeAudioObj.videoFormats.length; i++) {
 | 
				
			||||||
            const videoFormat = mimeAudioObj.videoFormats[i];
 | 
					            const videoFormat = mimeAudioObj.videoFormats[i];
 | 
				
			||||||
            if (isVideoFormat) {
 | 
					            if (isVideoFormat) {
 | 
				
			||||||
                    adapSet.elements.push(this.generate_representation_video(videoFormat));
 | 
					                adapSet.elements.push(generate_representation_video(videoFormat));
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                    adapSet.elements.push(this.generate_representation_audio(videoFormat));
 | 
					                adapSet.elements.push(generate_representation_audio(videoFormat));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        adaptationSets.push(adapSet);
 | 
					        adaptationSets.push(adapSet);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    return adaptationSets;
 | 
					    return adaptationSets;
 | 
				
			||||||
    },
 | 
					}
 | 
				
			||||||
    generate_representation_audio(Format) {
 | 
					
 | 
				
			||||||
 | 
					function generate_representation_audio(Format) {
 | 
				
			||||||
    const representation = {
 | 
					    const representation = {
 | 
				
			||||||
        type: "element",
 | 
					        type: "element",
 | 
				
			||||||
        name: "Representation",
 | 
					        name: "Representation",
 | 
				
			||||||
| 
						 | 
					@ -154,8 +159,9 @@ const DashUtils = {
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    return representation;
 | 
					    return representation;
 | 
				
			||||||
    },
 | 
					}
 | 
				
			||||||
    generate_representation_video(Format) {
 | 
					
 | 
				
			||||||
 | 
					function generate_representation_video(Format) {
 | 
				
			||||||
    const representation = {
 | 
					    const representation = {
 | 
				
			||||||
        type: "element",
 | 
					        type: "element",
 | 
				
			||||||
        name: "Representation",
 | 
					        name: "Representation",
 | 
				
			||||||
| 
						 | 
					@ -198,7 +204,4 @@ const DashUtils = {
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    return representation;
 | 
					    return representation;
 | 
				
			||||||
    },
 | 
					}
 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default DashUtils;
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue