Compare commits
1 Commits
master
...
disable-no
Author | SHA1 | Date |
---|---|---|
Émilien Devos | 72f03cd9de | 3 years ago |
@ -1,37 +0,0 @@
|
||||
name: Close duplicates
|
||||
on:
|
||||
issues:
|
||||
types: [opened]
|
||||
jobs:
|
||||
run:
|
||||
runs-on: ubuntu-latest
|
||||
permissions: write-all
|
||||
steps:
|
||||
- uses: iv-org/close-potential-duplicates@v1
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# Issue title filter work with anymatch https://www.npmjs.com/package/anymatch.
|
||||
# Any matched issue will stop detection immediately.
|
||||
# You can specify multi filters in each line.
|
||||
filter: ''
|
||||
# Exclude keywords in title before detecting.
|
||||
exclude: ''
|
||||
# Label to set, when potential duplicates are detected.
|
||||
label: duplicate
|
||||
# Get issues with state to compare. Supported state: 'all', 'closed', 'open'.
|
||||
state: open
|
||||
# If similarity is higher than this threshold([0,1]), issue will be marked as duplicate.
|
||||
threshold: 0.9
|
||||
# Reactions to be add to comment when potential duplicates are detected.
|
||||
# Available reactions: "-1", "+1", "confused", "laugh", "heart", "hooray", "rocket", "eyes"
|
||||
reactions: ''
|
||||
close: true
|
||||
# Comment to post when potential duplicates are detected.
|
||||
comment: |
|
||||
Hello, your issue is a duplicate of this/these issue(s): {{#issues}}
|
||||
- #{{ number }} [accuracy: {{ accuracy }}%]
|
||||
{{/issues}}
|
||||
|
||||
If this is a mistake please explain why and ping @\unixfox, @\SamantazFox and @\TheFrenchGhosty.
|
||||
|
||||
Please refrain from opening new issues, it won't help in solving your problem.
|
@ -1,3 +0,0 @@
|
||||
[submodule "mocks"]
|
||||
path = mocks
|
||||
url = ../mocks
|
@ -1,254 +0,0 @@
|
||||
'use strict';
|
||||
// Contains only auxiliary methods
|
||||
// May be included and executed unlimited number of times without any consequences
|
||||
|
||||
// Polyfills for IE11
|
||||
Array.prototype.find = Array.prototype.find || function (condition) {
|
||||
return this.filter(condition)[0];
|
||||
};
|
||||
|
||||
Array.from = Array.from || function (source) {
|
||||
return Array.prototype.slice.call(source);
|
||||
};
|
||||
NodeList.prototype.forEach = NodeList.prototype.forEach || function (callback) {
|
||||
Array.from(this).forEach(callback);
|
||||
};
|
||||
String.prototype.includes = String.prototype.includes || function (searchString) {
|
||||
return this.indexOf(searchString) >= 0;
|
||||
};
|
||||
String.prototype.startsWith = String.prototype.startsWith || function (prefix) {
|
||||
return this.substr(0, prefix.length) === prefix;
|
||||
};
|
||||
Math.sign = Math.sign || function(x) {
|
||||
x = +x;
|
||||
if (!x) return x; // 0 and NaN
|
||||
return x > 0 ? 1 : -1;
|
||||
};
|
||||
if (!window.hasOwnProperty('HTMLDetailsElement') && !window.hasOwnProperty('mockHTMLDetailsElement')) {
|
||||
window.mockHTMLDetailsElement = true;
|
||||
const style = 'details:not([open]) > :not(summary) {display: none}';
|
||||
document.head.appendChild(document.createElement('style')).textContent = style;
|
||||
|
||||
addEventListener('click', function (e) {
|
||||
if (e.target.nodeName !== 'SUMMARY') return;
|
||||
const details = e.target.parentElement;
|
||||
if (details.hasAttribute('open'))
|
||||
details.removeAttribute('open');
|
||||
else
|
||||
details.setAttribute('open', '');
|
||||
});
|
||||
}
|
||||
|
||||
// Monstrous global variable for handy code
|
||||
// Includes: clamp, xhr, storage.{get,set,remove}
|
||||
window.helpers = window.helpers || {
|
||||
/**
|
||||
* https://en.wikipedia.org/wiki/Clamping_(graphics)
|
||||
* @param {Number} num Source number
|
||||
* @param {Number} min Low border
|
||||
* @param {Number} max High border
|
||||
* @returns {Number} Clamped value
|
||||
*/
|
||||
clamp: function (num, min, max) {
|
||||
if (max < min) {
|
||||
var t = max; max = min; min = t; // swap max and min
|
||||
}
|
||||
|
||||
if (max < num)
|
||||
return max;
|
||||
if (min > num)
|
||||
return min;
|
||||
return num;
|
||||
},
|
||||
|
||||
/** @private */
|
||||
_xhr: function (method, url, options, callbacks) {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open(method, url);
|
||||
|
||||
// Default options
|
||||
xhr.responseType = 'json';
|
||||
xhr.timeout = 10000;
|
||||
// Default options redefining
|
||||
if (options.responseType)
|
||||
xhr.responseType = options.responseType;
|
||||
if (options.timeout)
|
||||
xhr.timeout = options.timeout;
|
||||
|
||||
if (method === 'POST')
|
||||
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
||||
|
||||
// better than onreadystatechange because of 404 codes https://stackoverflow.com/a/36182963
|
||||
xhr.onloadend = function () {
|
||||
if (xhr.status === 200) {
|
||||
if (callbacks.on200) {
|
||||
// fix for IE11. It doesn't convert response to JSON
|
||||
if (xhr.responseType === '' && typeof(xhr.response) === 'string')
|
||||
callbacks.on200(JSON.parse(xhr.response));
|
||||
else
|
||||
callbacks.on200(xhr.response);
|
||||
}
|
||||
} else {
|
||||
// handled by onerror
|
||||
if (xhr.status === 0) return;
|
||||
|
||||
if (callbacks.onNon200)
|
||||
callbacks.onNon200(xhr);
|
||||
}
|
||||
};
|
||||
|
||||
xhr.ontimeout = function () {
|
||||
if (callbacks.onTimeout)
|
||||
callbacks.onTimeout(xhr);
|
||||
};
|
||||
|
||||
xhr.onerror = function () {
|
||||
if (callbacks.onError)
|
||||
callbacks.onError(xhr);
|
||||
};
|
||||
|
||||
if (options.payload)
|
||||
xhr.send(options.payload);
|
||||
else
|
||||
xhr.send();
|
||||
},
|
||||
/** @private */
|
||||
_xhrRetry: function(method, url, options, callbacks) {
|
||||
if (options.retries <= 0) {
|
||||
console.warn('Failed to pull', options.entity_name);
|
||||
if (callbacks.onTotalFail)
|
||||
callbacks.onTotalFail();
|
||||
return;
|
||||
}
|
||||
helpers._xhr(method, url, options, callbacks);
|
||||
},
|
||||
/**
|
||||
* @callback callbackXhrOn200
|
||||
* @param {Object} response - xhr.response
|
||||
*/
|
||||
/**
|
||||
* @callback callbackXhrError
|
||||
* @param {XMLHttpRequest} xhr
|
||||
*/
|
||||
/**
|
||||
* @param {'GET'|'POST'} method - 'GET' or 'POST'
|
||||
* @param {String} url - URL to send request to
|
||||
* @param {Object} options - other XHR options
|
||||
* @param {XMLHttpRequestBodyInit} [options.payload=null] - payload for POST-requests
|
||||
* @param {'arraybuffer'|'blob'|'document'|'json'|'text'} [options.responseType=json]
|
||||
* @param {Number} [options.timeout=10000]
|
||||
* @param {Number} [options.retries=1]
|
||||
* @param {String} [options.entity_name='unknown'] - string to log
|
||||
* @param {Number} [options.retry_timeout=1000]
|
||||
* @param {Object} callbacks - functions to execute on events fired
|
||||
* @param {callbackXhrOn200} [callbacks.on200]
|
||||
* @param {callbackXhrError} [callbacks.onNon200]
|
||||
* @param {callbackXhrError} [callbacks.onTimeout]
|
||||
* @param {callbackXhrError} [callbacks.onError]
|
||||
* @param {callbackXhrError} [callbacks.onTotalFail] - if failed after all retries
|
||||
*/
|
||||
xhr: function(method, url, options, callbacks) {
|
||||
if (!options.retries || options.retries <= 1) {
|
||||
helpers._xhr(method, url, options, callbacks);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!options.entity_name) options.entity_name = 'unknown';
|
||||
if (!options.retry_timeout) options.retry_timeout = 1000;
|
||||
const retries_total = options.retries;
|
||||
let currentTry = 1;
|
||||
|
||||
const retry = function () {
|
||||
console.warn('Pulling ' + options.entity_name + ' failed... ' + (currentTry++) + '/' + retries_total);
|
||||
setTimeout(function () {
|
||||
options.retries--;
|
||||
helpers._xhrRetry(method, url, options, callbacks);
|
||||
}, options.retry_timeout);
|
||||
};
|
||||
|
||||
// Pack retry() call into error handlers
|
||||
callbacks._onError = callbacks.onError;
|
||||
callbacks.onError = function (xhr) {
|
||||
if (callbacks._onError)
|
||||
callbacks._onError(xhr);
|
||||
retry();
|
||||
};
|
||||
callbacks._onTimeout = callbacks.onTimeout;
|
||||
callbacks.onTimeout = function (xhr) {
|
||||
if (callbacks._onTimeout)
|
||||
callbacks._onTimeout(xhr);
|
||||
retry();
|
||||
};
|
||||
|
||||
helpers._xhrRetry(method, url, options, callbacks);
|
||||
},
|
||||
|
||||
/**
|
||||
* @typedef {Object} invidiousStorage
|
||||
* @property {(key:String) => Object} get
|
||||
* @property {(key:String, value:Object)} set
|
||||
* @property {(key:String)} remove
|
||||
*/
|
||||
|
||||
/**
|
||||
* Universal storage, stores and returns JS objects. Uses inside localStorage or cookies
|
||||
* @type {invidiousStorage}
|
||||
*/
|
||||
storage: (function () {
|
||||
// access to localStorage throws exception in Tor Browser, so try is needed
|
||||
let localStorageIsUsable = false;
|
||||
try{localStorageIsUsable = !!localStorage.setItem;}catch(e){}
|
||||
|
||||
if (localStorageIsUsable) {
|
||||
return {
|
||||
get: function (key) {
|
||||
let storageItem = localStorage.getItem(key)
|
||||
if (!storageItem) return;
|
||||
try {
|
||||
return JSON.parse(decodeURIComponent(storageItem));
|
||||
} catch(e) {
|
||||
// Erase non parsable value
|
||||
helpers.storage.remove(key);
|
||||
}
|
||||
},
|
||||
set: function (key, value) {
|
||||
let encoded_value = encodeURIComponent(JSON.stringify(value))
|
||||
localStorage.setItem(key, encoded_value);
|
||||
},
|
||||
remove: function (key) { localStorage.removeItem(key); }
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: fire 'storage' event for cookies
|
||||
console.info('Storage: localStorage is disabled or unaccessible. Cookies used as fallback');
|
||||
return {
|
||||
get: function (key) {
|
||||
const cookiePrefix = key + '=';
|
||||
function findCallback(cookie) {return cookie.startsWith(cookiePrefix);}
|
||||
const matchedCookie = document.cookie.split('; ').find(findCallback);
|
||||
if (matchedCookie) {
|
||||
const cookieBody = matchedCookie.replace(cookiePrefix, '');
|
||||
if (cookieBody.length === 0) return;
|
||||
try {
|
||||
return JSON.parse(decodeURIComponent(cookieBody));
|
||||
} catch(e) {
|
||||
// Erase non parsable value
|
||||
helpers.storage.remove(key);
|
||||
}
|
||||
}
|
||||
},
|
||||
set: function (key, value) {
|
||||
const cookie_data = encodeURIComponent(JSON.stringify(value));
|
||||
|
||||
// Set expiration in 2 year
|
||||
const date = new Date();
|
||||
date.setFullYear(date.getFullYear()+2);
|
||||
|
||||
document.cookie = key + '=' + cookie_data + '; expires=' + date.toGMTString();
|
||||
},
|
||||
remove: function (key) {
|
||||
document.cookie = key + '=; Max-Age=0';
|
||||
}
|
||||
};
|
||||
})()
|
||||
};
|
File diff suppressed because one or more lines are too long
@ -1,46 +1,91 @@
|
||||
'use strict';
|
||||
var toggle_theme = document.getElementById('toggle_theme');
|
||||
toggle_theme.href = 'javascript:void(0)';
|
||||
toggle_theme.href = 'javascript:void(0);';
|
||||
|
||||
const STORAGE_KEY_THEME = 'dark_mode';
|
||||
const THEME_DARK = 'dark';
|
||||
const THEME_LIGHT = 'light';
|
||||
|
||||
// TODO: theme state controlled by system
|
||||
toggle_theme.addEventListener('click', function () {
|
||||
const isDarkTheme = helpers.storage.get(STORAGE_KEY_THEME) === THEME_DARK;
|
||||
const newTheme = isDarkTheme ? THEME_LIGHT : THEME_DARK;
|
||||
setTheme(newTheme);
|
||||
helpers.storage.set(STORAGE_KEY_THEME, newTheme);
|
||||
helpers.xhr('GET', '/toggle_theme?redirect=false', {}, {});
|
||||
var dark_mode = document.body.classList.contains("light-theme");
|
||||
|
||||
var url = '/toggle_theme?redirect=false';
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.responseType = 'json';
|
||||
xhr.timeout = 10000;
|
||||
xhr.open('GET', url, true);
|
||||
|
||||
set_mode(dark_mode);
|
||||
try {
|
||||
window.localStorage.setItem('dark_mode', dark_mode ? 'dark' : 'light');
|
||||
} catch {}
|
||||
|
||||
xhr.send();
|
||||
});
|
||||
|
||||
/** @param {THEME_DARK|THEME_LIGHT} theme */
|
||||
function setTheme(theme) {
|
||||
// By default body element has .no-theme class that uses OS theme via CSS @media rules
|
||||
// It rewrites using hard className below
|
||||
if (theme === THEME_DARK) {
|
||||
toggle_theme.children[0].className = 'icon ion-ios-sunny';
|
||||
document.body.className = 'dark-theme';
|
||||
} else if (theme === THEME_LIGHT) {
|
||||
toggle_theme.children[0].className = 'icon ion-ios-moon';
|
||||
document.body.className = 'light-theme';
|
||||
} else {
|
||||
document.body.className = 'no-theme';
|
||||
window.addEventListener('storage', function (e) {
|
||||
if (e.key === 'dark_mode') {
|
||||
update_mode(e.newValue);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Handles theme change event caused by other tab
|
||||
addEventListener('storage', function (e) {
|
||||
if (e.key === STORAGE_KEY_THEME)
|
||||
setTheme(helpers.storage.get(STORAGE_KEY_THEME));
|
||||
window.addEventListener('DOMContentLoaded', function () {
|
||||
const dark_mode = document.getElementById('dark_mode_pref').textContent;
|
||||
try {
|
||||
// Update localStorage if dark mode preference changed on preferences page
|
||||
window.localStorage.setItem('dark_mode', dark_mode);
|
||||
} catch {}
|
||||
update_mode(dark_mode);
|
||||
});
|
||||
|
||||
// Set theme from preferences on page load
|
||||
addEventListener('DOMContentLoaded', function () {
|
||||
const prefTheme = document.getElementById('dark_mode_pref').textContent;
|
||||
if (prefTheme) {
|
||||
setTheme(prefTheme);
|
||||
helpers.storage.set(STORAGE_KEY_THEME, prefTheme);
|
||||
|
||||
var darkScheme = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
var lightScheme = window.matchMedia('(prefers-color-scheme: light)');
|
||||
|
||||
darkScheme.addListener(scheme_switch);
|
||||
lightScheme.addListener(scheme_switch);
|
||||
|
||||
function scheme_switch (e) {
|
||||
// ignore this method if we have a preference set
|
||||
try {
|
||||
if (localStorage.getItem('dark_mode')) {
|
||||
return;
|
||||
}
|
||||
});
|
||||
} catch {}
|
||||
if (e.matches) {
|
||||
if (e.media.includes("dark")) {
|
||||
set_mode(true);
|
||||
} else if (e.media.includes("light")) {
|
||||
set_mode(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function set_mode (bool) {
|
||||
if (bool) {
|
||||
// dark
|
||||
toggle_theme.children[0].setAttribute('class', 'icon ion-ios-sunny');
|
||||
document.body.classList.remove('no-theme');
|
||||
document.body.classList.remove('light-theme');
|
||||
document.body.classList.add('dark-theme');
|
||||
} else {
|
||||
// light
|
||||
toggle_theme.children[0].setAttribute('class', 'icon ion-ios-moon');
|
||||
document.body.classList.remove('no-theme');
|
||||
document.body.classList.remove('dark-theme');
|
||||
document.body.classList.add('light-theme');
|
||||
}
|
||||
}
|
||||
|
||||
function update_mode (mode) {
|
||||
if (mode === 'true' /* for backwards compatibility */ || mode === 'dark') {
|
||||
// If preference for dark mode indicated
|
||||
set_mode(true);
|
||||
}
|
||||
else if (mode === 'false' /* for backwards compatibility */ || mode === 'light') {
|
||||
// If preference for light mode indicated
|
||||
set_mode(false);
|
||||
}
|
||||
else if (document.getElementById('dark_mode_pref').textContent === '' && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||
// If no preference indicated here and no preference indicated on the preferences page (backend), but the browser tells us that the operating system has a dark theme
|
||||
set_mode(true);
|
||||
}
|
||||
// else do nothing, falling back to the mode defined by the `dark_mode` preference on the preferences page (backend)
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,24 +0,0 @@
|
||||
'use strict';
|
||||
var save_player_pos_key = 'save_player_pos';
|
||||
|
||||
function get_all_video_times() {
|
||||
return helpers.storage.get(save_player_pos_key) || {};
|
||||
}
|
||||
|
||||
document.querySelectorAll('.watched-indicator').forEach(function (indicator) {
|
||||
var watched_part = get_all_video_times()[indicator.dataset.id];
|
||||
var total = parseInt(indicator.dataset.length, 10);
|
||||
if (watched_part === undefined) {
|
||||
watched_part = total;
|
||||
}
|
||||
var percentage = Math.round((watched_part / total) * 100);
|
||||
|
||||
if (percentage < 5) {
|
||||
percentage = 5;
|
||||
}
|
||||
if (percentage > 90) {
|
||||
percentage = 100;
|
||||
}
|
||||
|
||||
indicator.style.width = percentage + '%';
|
||||
});
|
@ -1,6 +1,6 @@
|
||||
dependencies:
|
||||
- name: postgresql
|
||||
repository: https://charts.bitnami.com/bitnami/
|
||||
version: 12.1.9
|
||||
digest: sha256:71ff342a6c0a98bece3d7fe199983afb2113f8db65a3e3819de875af2c45add7
|
||||
generated: "2023-01-20T20:42:32.757707004Z"
|
||||
repository: https://kubernetes-charts.storage.googleapis.com/
|
||||
version: 8.3.0
|
||||
digest: sha256:1feec3c396cbf27573dc201831ccd3376a4a6b58b2e7618ce30a89b8f5d707fd
|
||||
generated: "2020-02-07T13:39:38.624846+01:00"
|
||||
|
@ -1 +0,0 @@
|
||||
{}
|
@ -1,94 +0,0 @@
|
||||
{
|
||||
"Subscribe": "সাবস্ক্রাইব",
|
||||
"View channel on YouTube": "ইউটিউবে চ্যানেল দেখুন",
|
||||
"View playlist on YouTube": "ইউটিউবে প্লেলিস্ট দেখুন",
|
||||
"newest": "সর্ব-নতুন",
|
||||
"oldest": "পুরানতম",
|
||||
"popular": "জনপ্রিয়",
|
||||
"last": "শেষটা",
|
||||
"Next page": "পরের পৃষ্ঠা",
|
||||
"Previous page": "আগের পৃষ্ঠা",
|
||||
"Clear watch history?": "দেখার ইতিহাস সাফ করবেন?",
|
||||
"New password": "নতুন পাসওয়ার্ড",
|
||||
"New passwords must match": "নতুন পাসওয়ার্ড অবশ্যই মিলতে হবে",
|
||||
"Authorize token?": "টোকেন অনুমোদন করবেন?",
|
||||
"Authorize token for `x`?": "`x` -এর জন্য টোকেন অনুমোদন?",
|
||||
"Yes": "হ্যাঁ",
|
||||
"No": "না",
|
||||
"Import and Export Data": "তথ্য আমদানি ও রপ্তানি",
|
||||
"Import": "আমদানি",
|
||||
"Import Invidious data": "ইনভিডিয়াস তথ্য আমদানি",
|
||||
"Import YouTube subscriptions": "ইউটিউব সাবস্ক্রিপশন আনুন",
|
||||
"Import FreeTube subscriptions (.db)": "ফ্রিটিউব সাবস্ক্রিপশন (.db) আনুন",
|
||||
"Import NewPipe subscriptions (.json)": "নতুন পাইপ সাবস্ক্রিপশন আনুন (.json)",
|
||||
"Import NewPipe data (.zip)": "নিউপাইপ তথ্য আনুন (.zip)",
|
||||
"Export": "তথ্য বের করুন",
|
||||
"Export subscriptions as OPML": "সাবস্ক্রিপশন OPML হিসাবে আনুন",
|
||||
"Export subscriptions as OPML (for NewPipe & FreeTube)": "OPML-এ সাবস্ক্রিপশন বের করুন(নিউ পাইপ এবং ফ্রিউটিউব এর জন্য)",
|
||||
"Export data as JSON": "JSON হিসাবে তথ্য বের করুন",
|
||||
"Delete account?": "অ্যাকাউন্ট মুছে ফেলবেন?",
|
||||
"History": "ইতিহাস",
|
||||
"An alternative front-end to YouTube": "ইউটিউবের একটি বিকল্পস্বরূপ সম্মুখ-প্রান্ত",
|
||||
"JavaScript license information": "জাভাস্ক্রিপ্ট লাইসেন্সের তথ্য",
|
||||
"source": "সূত্র",
|
||||
"Log in": "লগ ইন",
|
||||
"Log in/register": "লগ ইন/রেজিস্টার",
|
||||
"User ID": "ইউজার আইডি",
|
||||
"Password": "পাসওয়ার্ড",
|
||||
"Time (h:mm:ss):": "সময় (ঘণ্টা:মিনিট:সেকেন্ড):",
|
||||
"Text CAPTCHA": "টেক্সট ক্যাপচা",
|
||||
"Image CAPTCHA": "চিত্র ক্যাপচা",
|
||||
"Sign In": "সাইন ইন",
|
||||
"Register": "নিবন্ধন",
|
||||
"E-mail": "ই-মেইল",
|
||||
"Preferences": "পছন্দসমূহ",
|
||||
"preferences_category_player": "প্লেয়ারের পছন্দসমূহ",
|
||||
"preferences_video_loop_label": "সর্বদা লুপ: ",
|
||||
"preferences_autoplay_label": "স্বয়ংক্রিয় চালু: ",
|
||||
"preferences_continue_label": "ডিফল্টভাবে পরবর্তী চালাও: ",
|
||||
"preferences_continue_autoplay_label": "পরবর্তী ভিডিও স্বয়ংক্রিয়ভাবে চালাও: ",
|
||||
"preferences_listen_label": "সহজাতভাবে শোনো: ",
|
||||
"preferences_local_label": "ভিডিও প্রক্সি করো: ",
|
||||
"preferences_speed_label": "সহজাত গতি: ",
|
||||
"preferences_quality_label": "পছন্দের ভিডিও মান: ",
|
||||
"preferences_volume_label": "প্লেয়ার শব্দের মাত্রা: ",
|
||||
"LIVE": "লাইভ",
|
||||
"Shared `x` ago": "`x` আগে শেয়ার করা হয়েছে",
|
||||
"Unsubscribe": "আনসাবস্ক্রাইব",
|
||||
"generic_views_count": "{{count}}জন দেখেছে",
|
||||
"generic_views_count_plural": "{{count}}জন দেখেছে",
|
||||
"generic_videos_count": "{{count}}টি ভিডিও",
|
||||
"generic_videos_count_plural": "{{count}}টি ভিডিও",
|
||||
"generic_subscribers_count": "{{count}}জন অনুসরণকারী",
|
||||
"generic_subscribers_count_plural": "{{count}}জন অনুসরণকারী",
|
||||
"preferences_watch_history_label": "দেখার ইতিহাস চালু করো: ",
|
||||
"preferences_quality_option_dash": "ড্যাশ (সময়োপযোগী মান)",
|
||||
"preferences_quality_dash_option_auto": "স্বয়ংক্রিয়",
|
||||
"preferences_quality_dash_option_best": "সেরা",
|
||||
"preferences_quality_dash_option_worst": "মন্দতম",
|
||||
"preferences_quality_dash_option_4320p": "৪৩২০পি",
|
||||
"preferences_quality_dash_option_2160p": "২১৬০পি",
|
||||
"preferences_quality_dash_option_1440p": "১৪৪০পি",
|
||||
"preferences_quality_dash_option_480p": "৪৮০পি",
|
||||
"preferences_quality_dash_option_360p": "৩৬০পি",
|
||||
"preferences_quality_dash_option_240p": "২৪০পি",
|
||||
"preferences_quality_dash_option_144p": "১৪৪পি",
|
||||
"preferences_comments_label": "সহজাত মন্তব্য: ",
|
||||
"youtube": "ইউটিউব",
|
||||
"Fallback captions: ": "বিকল্প উপাখ্যান: ",
|
||||
"preferences_related_videos_label": "সম্পর্কিত ভিডিও দেখাও: ",
|
||||
"preferences_annotations_label": "সহজাতভাবে টীকা দেখাও ",
|
||||
"preferences_quality_option_hd720": "উচ্চ৭২০",
|
||||
"preferences_quality_dash_label": "পছন্দের ড্যাশ ভিডিও মান: ",
|
||||
"preferences_captions_label": "সহজাত উপাখ্যান: ",
|
||||
"generic_playlists_count": "{{count}}টি চালুতালিকা",
|
||||
"generic_playlists_count_plural": "{{count}}টি চালুতালিকা",
|
||||
"reddit": "রেডিট",
|
||||
"invidious": "ইনভিডিয়াস",
|
||||
"generic_subscriptions_count": "{{count}}টি অনুসরণ",
|
||||
"generic_subscriptions_count_plural": "{{count}}টি অনুসরণ",
|
||||
"preferences_quality_option_medium": "মধ্যম",
|
||||
"preferences_quality_option_small": "ছোট",
|
||||
"preferences_quality_dash_option_1080p": "১০৮০পি",
|
||||
"preferences_quality_dash_option_720p": "৭২০পি"
|
||||
}
|
@ -1,332 +0,0 @@
|
||||
{
|
||||
"generic_playlists_count": "{{count}} esitusloend",
|
||||
"generic_playlists_count_plural": "{{count}} esindusloendit",
|
||||
"LIVE": "OTSEÜLEKANNE",
|
||||
"View channel on YouTube": "Vaata kanalit YouTube'is",
|
||||
"Log in": "Logi sisse",
|
||||
"Log in/register": "Logi sisse/registreeru",
|
||||
"Dark mode: ": "Tume režiim: ",
|
||||
"generic_videos_count": "{{count}} video",
|
||||
"generic_videos_count_plural": "{{count}} videot",
|
||||
"generic_subscribers_count": "{{count}} tellija",
|
||||
"generic_subscribers_count_plural": "{{count}} tellijat",
|
||||
"generic_subscriptions_count": "{{count}} tellimus",
|
||||
"generic_subscriptions_count_plural": "{{count}} tellimust",
|
||||
"Shared `x` ago": "Jagatud `x` tagasi",
|
||||
"Unsubscribe": "Loobu tellimusest",
|
||||
"Subscribe": "Telli",
|
||||
"View playlist on YouTube": "Vaata esitusloendit YouTube'is",
|
||||
"newest": "uusimad",
|
||||
"oldest": "vanimad",
|
||||
"popular": "populaarsed",
|
||||
"last": "viimane",
|
||||
"Next page": "Järgmine leht",
|
||||
"Previous page": "Eelmine leht",
|
||||
"Clear watch history?": "Kustuta vaatamiste ajalugu?",
|
||||
"New password": "Uus salasõna",
|
||||
"New passwords must match": "Uued salasõnad peavad ühtima",
|
||||
"Import and Export Data": "Impordi ja ekspordi andmed",
|
||||
"Import": "Impordi",
|
||||
"Import YouTube subscriptions": "Impordi tellimused Youtube'ist/OPML-ist",
|
||||
"Import FreeTube subscriptions (.db)": "Impordi tellimused FreeTube'ist (.db)",
|
||||
"Import NewPipe data (.zip)": "Impordi NewPipe'i andmed (.zip)",
|
||||
"Export": "Ekspordi",
|
||||
"Export subscriptions as OPML": "Ekspordi tellimused OPML-ina",
|
||||
"Export subscriptions as OPML (for NewPipe & FreeTube)": "Ekspordi tellimused OPML-ina (NewPipe'i ja FreeTube'i jaoks)",
|
||||
"Delete account?": "Kustuta kasutaja?",
|
||||
"History": "Ajalugu",
|
||||
"JavaScript license information": "JavaScripti litsentsi info",
|
||||
"source": "allikas",
|
||||
"User ID": "Kasutada ID",
|
||||
"Password": "Salasõna",
|
||||
"Time (h:mm:ss):": "Aeg (h:mm:ss):",
|
||||
"Text CAPTCHA": "CAPTCHA-tekst",
|
||||
"Image CAPTCHA": "CAPTCHA-foto",
|
||||
"Sign In": "Logi sisse",
|
||||
"Register": "Registreeru",
|
||||
"E-mail": "E-post",
|
||||
"Preferences": "Eelistused",
|
||||
"preferences_category_player": "Mängija eelistused",
|
||||
"preferences_continue_autoplay_label": "Mängi järgmine video automaatselt: ",
|
||||
"preferences_quality_label": "Eelistatud videokvaliteet: ",
|
||||
"preferences_quality_option_dash": "DASH (kohanduv kvaliteet)",
|
||||
"preferences_quality_option_hd720": "HD720",
|
||||
"preferences_quality_option_medium": "Keskmine",
|
||||
"preferences_quality_option_small": "Väike",
|
||||
"preferences_quality_dash_label": "Eelistatav DASH-video kvaliteet: ",
|
||||
"preferences_quality_dash_option_auto": "Automaatne",
|
||||
"preferences_quality_dash_option_best": "Parim",
|
||||
"preferences_quality_dash_option_worst": "Halvim",
|
||||
"preferences_volume_label": "Video helitugevus: ",
|
||||
"youtube": "YouTube",
|
||||
"reddit": "Reddit",
|
||||
"preferences_related_videos_label": "Näita sarnaseid videosid: ",
|
||||
"preferences_vr_mode_label": "Interaktiivne 360-kraadine video (vajalik WebGL): ",
|
||||
"preferences_dark_mode_label": "Teema: ",
|
||||
"dark": "tume",
|
||||
"light": "hele",
|
||||
"preferences_category_subscription": "Tellimuse seaded",
|
||||
"preferences_max_results_label": "Avalehel näidatavate videote arv: ",
|
||||
"preferences_sort_label": "Sorteeri: ",
|
||||
"published": "avaldatud",
|
||||
"alphabetically": "tähestikulises järjekorras",
|
||||
"alphabetically - reverse": "vastupidi tähestikulises järjekorras",
|
||||
"channel name": "kanali nimi",
|
||||
"preferences_unseen_only_label": "Näita ainult vaatamata videosid: ",
|
||||
"Only show latest video from channel: ": "Näita ainult viimast videot: ",
|
||||
"preferences_notifications_only_label": "Näita ainult teavitusi (kui neid on): ",
|
||||
"Enable web notifications": "Luba veebiteavitused",
|
||||
"`x` uploaded a video": "`x` laadis video üles",
|
||||
"`x` is live": "`x` teeb otseülekannet",
|
||||
"preferences_category_data": "Andme-eelistused",
|
||||
"Clear watch history": "Puhasta vaatamisajalugu",
|
||||
"Import/export data": "Impordi/ekspordi andmed",
|
||||
"Change password": "Muuda salasõna",
|
||||
"Watch history": "Vaatamisajalugu",
|
||||
"Delete account": "Kustuta kasutaja",
|
||||
"Save preferences": "Salvesta eelistused",
|
||||
"Token": "Token",
|
||||
"Import/export": "Imprort/eksport",
|
||||
"unsubscribe": "loobu tellimusest",
|
||||
"Subscriptions": "Tellimused",
|
||||
"search": "otsi",
|
||||
"Source available here.": "Allikas on kättesaadaval siin.",
|
||||
"View privacy policy.": "Vaata privaatsuspoliitikat.",
|
||||
"Public": "Avalik",
|
||||
"Private": "Privaatne",
|
||||
"View all playlists": "Vaata kõiki esitusloendeid",
|
||||
"Updated `x` ago": "Uuendas `x` tagasi",
|
||||
"Delete playlist `x`?": "Kustuta esitusloend `x`?",
|
||||
"Delete playlist": "Kustuta esitusloend",
|
||||
"Create playlist": "Loo esitlusloend",
|
||||
"Title": "Pealkiri",
|
||||
"Playlist privacy": "Esitusloendi privaatsus",
|
||||
"Show more": "Näita rohkem",
|
||||
"Show less": "Näita vähem",
|
||||
"Watch on YouTube": "Vaata YouTube'is",
|
||||
"search_message_no_results": "Tulemusi ei leitud.",
|
||||
"search_message_change_filters_or_query": "Proovi otsingut laiendada või filtreid muuta.",
|
||||
"Genre: ": "Žanr: ",
|
||||
"License: ": "Litsents: ",
|
||||
"Family friendly? ": "Peresõbralik? ",
|
||||
"Shared `x`": "Jagas `x`",
|
||||
"Premieres in `x`": "Esilinastub `x`",
|
||||
"Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "Tundub, et oled JavaScripti välja lülitanud. Vajuta siia, et kommentaare vaadata; nende laadimine võib võtta natukene rohkem aega.",
|
||||
"View Reddit comments": "Vaata Redditi kommentaare",
|
||||
"Hide replies": "Peida vastused",
|
||||
"Show replies": "Näita vastuseid",
|
||||
"Incorrect password": "Vale salasõna",
|
||||
"Wrong answer": "Vale vastus",
|
||||
"User ID is a required field": "Kasutaja ID on kohustuslik väli",
|
||||
"Password is a required field": "Salasõna on kohustuslik väli",
|
||||
"Wrong username or password": "Vale kasutajanimi või salasõna",
|
||||
"Password cannot be longer than 55 characters": "Salasõna ei tohi olla pikem kui 55 tähemärki",
|
||||
"Password cannot be empty": "Salasõna ei tohi olla tühi",
|
||||
"Please log in": "Palun logige sisse",
|
||||
"channel:`x`": "kanal:`x`",
|
||||
"Deleted or invalid channel": "Kanal on kustutatud või seda ei leitud",
|
||||
"This channel does not exist.": "Sellist kanalit pole olemas.",
|
||||
"comments_view_x_replies": "{{count}} vastus",
|
||||
"comments_view_x_replies_plural": "{{count}} vastust",
|
||||
"`x` ago": "`x` tagasi",
|
||||
"Load more": "Laadi rohkem",
|
||||
"Empty playlist": "Tühi esitusloend",
|
||||
"Not a playlist.": "Tegu pole esitusloendiga.",
|
||||
"Playlist does not exist.": "Seda esitusloendit pole olemas.",
|
||||
"No such user": "Sellist kasutajat pole",
|
||||
"English": "Inglise",
|
||||
"English (United Kingdom)": "Inglise (Suurbritannia)",
|
||||
"English (United States)": "Inglise (USA)",
|
||||
"English (auto-generated)": "Inglise (automaatselt koostatud)",
|
||||
"Afrikaans": "Afrikaani",
|
||||
"Albanian": "Albaania",
|
||||
"Arabic": "Araabia",
|
||||
"Armenian": "Armeenia",
|
||||
"Bangla": "Bengali",
|
||||
"Basque": "Baski",
|
||||
"Belarusian": "Valgevene",
|
||||
"Bulgarian": "Bulgaaria",
|
||||
"Burmese": "Birma",
|
||||
"Cantonese (Hong Kong)": "Kantoni (Hong Konk)",
|
||||
"Chinese (China)": "Hiina (Hiina)",
|
||||
"Chinese (Hong Kong)": "Hiina (Hong Kong)",
|
||||
"Chinese (Simplified)": "Hiina (lihtsustatud)",
|
||||
"Chinese (Taiwan)": "Hiina (Taiwan)",
|
||||
"Croatian": "Horvaatia",
|
||||
"Czech": "Tšehhi",
|
||||
"Danish": "Taani",
|
||||
"Dutch": "Hollandi",
|
||||
"Esperanto": "Esperanto",
|
||||
"Estonian": "Eesti",
|
||||
"Filipino": "Filipiini",
|
||||
"Finnish": "Soome",
|
||||
"French": "Prantsuse",
|
||||
"French (auto-generated)": "Prantsuse (automaatne)",
|
||||
"Dutch (auto-generated)": "Hollandi (automaatne)",
|
||||
"Galician": "Kaliitsia",
|
||||
"Georgian": "Gruusia",
|
||||
"Haitian Creole": "Haiti kreool",
|
||||
"Hausa": "Hausa",
|
||||
"Hawaiian": "Havaii",
|
||||
"Hebrew": "Heebrea",
|
||||
"Hindi": "Hindi",
|
||||
"Hungarian": "Ungari",
|
||||
"Icelandic": "Islandi",
|
||||
"Indonesian": "Indoneesia",
|
||||
"Japanese (auto-generated)": "Jaapani (automaatne)",
|
||||
"Kannada": "Kannada",
|
||||
"Kazakh": "Kasahhi",
|
||||
"Luxembourgish": "Luksemburgi",
|
||||
"Macedonian": "Makedoonia",
|
||||
"Malay": "Malai",
|
||||
"Maltese": "Malta",
|
||||
"Maori": "Maori",
|
||||
"Marathi": "Marathi",
|
||||
"Mongolian": "Mongoli",
|
||||
"Nepali": "Nepaali",
|
||||
"Norwegian Bokmål": "Norra (Bokmål)",
|
||||
"Persian": "Pärsia",
|
||||
"Polish": "Poola",
|
||||
"Portuguese": "Portugali",
|
||||
"Portuguese (auto-generated)": "Portugali (automaatne)",
|
||||
"Portuguese (Brazil)": "Portugali (Brasiilia)",
|
||||
"Romanian": "Rumeenia",
|
||||
"Russian": "Vene",
|
||||
"Russian (auto-generated)": "Vene (automaatne)",
|
||||
"Scottish Gaelic": "Šoti (Gaeli)",
|
||||
"Serbian": "Serbia",
|
||||
"Slovak": "Slovaki",
|
||||
"Slovenian": "Sloveeni",
|
||||
"Somali": "Somaali",
|
||||
"Spanish": "Hispaania",
|
||||
"Spanish (auto-generated)": "Hispaania (automaatne)",
|
||||
"Spanish (Latin America)": "Hispaania (Ladina-Ameerika)",
|
||||
"Spanish (Mexico)": "Hispaania (Mehhiko)",
|
||||
"Spanish (Spain)": "Hispaania (Hispaania)",
|
||||
"Swahili": "Suahili",
|
||||
"Swedish": "Rootsi",
|
||||
"Tajik": "Tadžiki",
|
||||
"Tamil": "Tamiili",
|
||||
"Thai": "Tai",
|
||||
"Turkish": "Türgi",
|
||||
"Turkish (auto-generated)": "Türgi (automaatne)",
|
||||
"Ukrainian": "Ukraina",
|
||||
"Uzbek": "Usbeki",
|
||||
"Vietnamese": "Vietnami",
|
||||
"Vietnamese (auto-generated)": "Vietnami (automaatne)",
|
||||
"generic_count_years": "{{count}} aasta",
|
||||
"generic_count_years_plural": "{{count}} aastat",
|
||||
"generic_count_months": "{{count}} kuu",
|
||||
"generic_count_months_plural": "{{count}} kuud",
|
||||
"generic_count_weeks": "{{count}} nädal",
|
||||
"generic_count_weeks_plural": "{{count}} nädalat",
|
||||
"generic_count_days": "{{count}} päev",
|
||||
"generic_count_days_plural": "{{count}} päeva",
|
||||
"generic_count_hours": "{{count}} tund",
|
||||
"generic_count_hours_plural": "{{count}} tundi",
|
||||
"generic_count_minutes": "{{count}} minut",
|
||||
"generic_count_minutes_plural": "{{count}} minutit",
|
||||
"Popular": "Populaarne",
|
||||
"Search": "Otsi",
|
||||
"Top": "Top",
|
||||
"About": "Leheküljest",
|
||||
"preferences_locale_label": "Keel: ",
|
||||
"View as playlist": "Vaata esitusloendina",
|
||||
"Movies": "Filmid",
|
||||
"Download as: ": "Laadi kui: ",
|
||||
"(edited)": "(muudetud)",
|
||||
"`x` marked it with a ❤": "`x` märkis ❤",
|
||||
"Audio mode": "Audiorežiim",
|
||||
"Video mode": "Videorežiim",
|
||||
"search_filters_date_label": "Üleslaadimise kuupäev",
|
||||
"search_filters_date_option_none": "Ükskõik mis kuupäev",
|
||||
"search_filters_date_option_today": "Täna",
|
||||
"search_filters_date_option_week": "Sel nädalal",
|
||||
"search_filters_date_option_hour": "Viimasel tunnil",
|
||||
"search_filters_date_option_month": "Sel kuul",
|
||||
"search_filters_date_option_year": "Sel aastal",
|
||||
"search_filters_type_label": "Tüüp",
|
||||
"search_filters_type_option_all": "Ükskõik mis tüüp",
|
||||
"search_filters_duration_label": "Kestus",
|
||||
"search_filters_type_option_show": "Näita",
|
||||
"search_filters_duration_option_none": "Ükskõik mis kestus",
|
||||
"search_filters_duration_option_short": "Lühike (alla 4 minuti)",
|
||||
"search_filters_duration_option_medium": "Keskmine (4 - 20 minutit)",
|
||||
"search_filters_duration_option_long": "Pikk (üle 20 minuti)",
|
||||
"search_filters_features_option_live": "Otseülekanne",
|
||||
"search_filters_features_option_four_k": "4K",
|
||||
"search_filters_features_option_hd": "HD",
|
||||
"search_filters_features_option_subtitles": "Subtiitrid",
|
||||
"search_filters_features_option_location": "Asukoht",
|
||||
"search_filters_sort_label": "Sorteeri",
|
||||
"search_filters_sort_option_views": "Vaatamiste arv",
|
||||
"next_steps_error_message": "Pärast mida võiksite proovida: ",
|
||||
"videoinfo_started_streaming_x_ago": "Alustas otseülekannet `x` tagasi",
|
||||
"Yes": "Jah",
|
||||
"generic_views_count": "{{count}} vaatamine",
|
||||
"generic_views_count_plural": "{{count}} vaatamist",
|
||||
"Import NewPipe subscriptions (.json)": "Impordi tellimused NewPipe'ist (.json)",
|
||||
"No": "Ei",
|
||||
"preferences_region_label": "Riik: ",
|
||||
"View YouTube comments": "Vaata YouTube'i kommentaare",
|
||||
"preferences_extend_desc_label": "Ava video kirjeldus automaatselt: ",
|
||||
"German (auto-generated)": "Saksa (automaatne)",
|
||||
"Italian": "Itaalia",
|
||||
"preferences_player_style_label": "Mängija stiil: ",
|
||||
"subscriptions_unseen_notifs_count": "{{count}} lugemata teavitus",
|
||||
"subscriptions_unseen_notifs_count_plural": "{{count}} lugemata teavitust",
|
||||
"View more comments on Reddit": "Vaata teisi kommentaare Redditis",
|
||||
"Only show latest unwatched video from channel: ": "Näita ainult viimast vaatamata videot: ",
|
||||
"tokens_count": "{{count}} token",
|
||||
"tokens_count_plural": "{{count}} tokenit",
|
||||
"Log out": "Logi välja",
|
||||
"Premieres `x`": "Linastub`x`",
|
||||
"View `x` comments": {
|
||||
"([^.,0-9]|^)1([^.,0-9]|$)": "Vaata `x` kommentaari",
|
||||
"": "Vaata `x` kommentaare"
|
||||
},
|
||||
"Khmer": "Khmeeri",
|
||||
"Bosnian": "Bosnia",
|
||||
"Corsican": "Korsika",
|
||||
"Javanese": "Jaava",
|
||||
"Lithuanian": "Leedu",
|
||||
"channel_tab_videos_label": "Videod",
|
||||
"channel_tab_community_label": "Kogukond",
|
||||
"CAPTCHA is a required field": "CAPTCHA on kohustuslik väli",
|
||||
"comments_points_count": "{{count}} punkt",
|
||||
"comments_points_count_plural": "{{count}} punkti",
|
||||
"Chinese": "Hiina",
|
||||
"German": "Saksa",
|
||||
"Indonesian (auto-generated)": "Indoneesia (automaatne)",
|
||||
"Italian (auto-generated)": "Itaalia (automaatne)",
|
||||
"Kyrgyz": "Kirkiisi",
|
||||
"Latin": "Ladina",
|
||||
"generic_count_seconds": "{{count}} sekund",
|
||||
"generic_count_seconds_plural": "{{count}} sekundit",
|
||||
"Catalan": "Katalaani",
|
||||
"Chinese (Traditional)": "Hiina (traditsiooniline)",
|
||||
"Greek": "Kreeka",
|
||||
"Kurdish": "Kurdi",
|
||||
"Latvian": "Läti",
|
||||
"Irish": "Iiri",
|
||||
"Korean": "Korea",
|
||||
"Japanese": "Jaapani",
|
||||
"Korean (auto-generated)": "Korea (automaatne)",
|
||||
"Music": "Muusika",
|
||||
"Playlists": "Esitusloendid",
|
||||
"search_filters_type_option_video": "Video",
|
||||
"search_filters_sort_option_date": "Üleslaadimise kuupäev",
|
||||
"Current version: ": "Praegune versioon: ",
|
||||
"footer_documentation": "Dokumentatsioon",
|
||||
"Gaming": "Mängud",
|
||||
"News": "Uudised",
|
||||
"Download": "Laadi alla",
|
||||
"search_filters_title": "Filtrid",
|
||||
"search_filters_type_option_channel": "Kanal",
|
||||
"search_filters_type_option_playlist": "Esitusloend",
|
||||
"search_filters_type_option_movie": "Film",
|
||||
"next_steps_error_message_go_to_youtube": "Minna YouTube'i",
|
||||
"next_steps_error_message_refresh": "Laadida uuesti",
|
||||
"footer_donate_page": "Anneta",
|
||||
"videoinfo_watch_on_youTube": "Vaata YouTube'is"
|
||||
}
|
@ -1,475 +0,0 @@
|
||||
{
|
||||
"last": "आखिरी",
|
||||
"Yes": "हाँ",
|
||||
"No": "नहीं",
|
||||
"Export subscriptions as OPML (for NewPipe & FreeTube)": "OPML के रूप में सदस्यताएँ निर्यात करें (NewPipe और FreeTube के लिए)",
|
||||
"Log in/register": "लॉग-इन/पंजीकृत करें",
|
||||
"preferences_autoplay_label": "अपने आप चलाने की सुविधा: ",
|
||||
"preferences_dark_mode_label": "थीम: ",
|
||||
"preferences_default_home_label": "डिफ़ॉल्ट मुखपृष्ठ: ",
|
||||
"Could not fetch comments": "टिप्पणियाँ प्राप्त न की जा सकीं",
|
||||
"comments_points_count": "{{count}} पॉइंट",
|
||||
"comments_points_count_plural": "{{count}} पॉइंट्स",
|
||||
"Subscription manager": "सदस्यता प्रबंधन",
|
||||
"License: ": "लाइसेंस: ",
|
||||
"Wilson score: ": "Wilson स्कोर: ",
|
||||
"Wrong answer": "गलत जवाब",
|
||||
"Erroneous CAPTCHA": "गलत CAPTCHA",
|
||||
"Please log in": "कृपया लॉग-इन करें",
|
||||
"Bosnian": "बोस्नियाई",
|
||||
"Bulgarian": "बुल्गारियाई",
|
||||
"Burmese": "बर्मी",
|
||||
"Chinese (Traditional)": "चीनी (पारंपरिक)",
|
||||
"Kurdish": "कुर्द",
|
||||
"Punjabi": "पंजाबी",
|
||||
"Sinhala": "सिंहली",
|
||||
"Slovak": "स्लोवाक",
|
||||
"generic_count_days": "{{count}} दिन",
|
||||
"generic_count_days_plural": "{{count}} दिन",
|
||||
"generic_count_hours": "{{count}} घंटे",
|
||||
"generic_count_hours_plural": "{{count}} घंटे",
|
||||
"generic_count_minutes": "{{count}} मिनट",
|
||||
"generic_count_minutes_plural": "{{count}} मिनट",
|
||||
"generic_count_seconds": "{{count}} सेकंड",
|
||||
"generic_count_seconds_plural": "{{count}} सेकंड",
|
||||
"generic_playlists_count": "{{count}} प्लेलिस्ट",
|
||||
"generic_playlists_count_plural": "{{count}} प्लेलिस्ट्स",
|
||||
"crash_page_report_issue": "अगर इनमें से कुछ भी काम नहीं करता, कृपया <a href=\"`x`\">GitHub पर एक नया मुद्दा खोल दें</a> (अंग्रेज़ी में) और अपने संदेश में यह टेक्स्ट दर्ज करें (इसे अनुवादित न करें!):",
|
||||
"generic_views_count": "{{count}} बार देखा गया",
|
||||
"generic_views_count_plural": "{{count}} बार देखा गया",
|
||||
"generic_videos_count": "{{count}} वीडियो",
|
||||
"generic_videos_count_plural": "{{count}} वीडियो",
|
||||
"generic_subscribers_count": "{{count}} सदस्य",
|
||||
"generic_subscribers_count_plural": "{{count}} सदस्य",
|
||||
"generic_subscriptions_count": "{{count}} सदस्यता",
|
||||
"generic_subscriptions_count_plural": "{{count}} सदस्यताएँ",
|
||||
"LIVE": "लाइव",
|
||||
"Shared `x` ago": "`x` पहले बाँटा गया",
|
||||
"Unsubscribe": "सदस्यता छोड़ें",
|
||||
"Subscribe": "सदस्यता लें",
|
||||
"View channel on YouTube": "चैनल YouTube पर देखें",
|
||||
"View playlist on YouTube": "प्लेलिस्ट YouTube पर देखें",
|
||||
"newest": "सबसे नया",
|
||||
"oldest": "सबसे पुराना",
|
||||
"popular": "सर्वाधिक लोकप्रिय",
|
||||
"Next page": "अगला पृष्ठ",
|
||||
"Previous page": "पिछला पृष्ठ",
|
||||
"Clear watch history?": "देखने का इतिहास मिटाएँ?",
|
||||
"New password": "नया पासवर्ड",
|
||||
"New passwords must match": "पासवर्ड्स को मेल खाना होगा",
|
||||
"Authorize token?": "टोकन को प्रमाणित करें?",
|
||||
"Authorize token for `x`?": "`x` के लिए टोकन को प्रमाणित करें?",
|
||||
"Import and Export Data": "डेटा को आयात और निर्यात करें",
|
||||
"Import": "आयात करें",
|
||||
"Import Invidious data": "Invidious JSON डेटा आयात करें",
|
||||
"Import YouTube subscriptions": "YouTube/OPML सदस्यताएँ आयात करें",
|
||||
"Import FreeTube subscriptions (.db)": "FreeTube सदस्यताएँ आयात करें (.db)",
|
||||
"Import NewPipe subscriptions (.json)": "NewPipe सदस्यताएँ आयात करें (.json)",
|
||||
"Import NewPipe data (.zip)": "NewPipe डेटा आयात करें (.zip)",
|
||||
"Export": "निर्यात करें",
|
||||
"Export subscriptions as OPML": "OPML के रूप में सदस्यताएँ निर्यात करें",
|
||||
"Export data as JSON": "Invidious डेटा को JSON के रूप में निर्यात करें",
|
||||
"Delete account?": "खाता हटाएँ?",
|
||||
"History": "देखे गए वीडियो",
|
||||
"An alternative front-end to YouTube": "YouTube का एक वैकल्पिक फ्रंट-एंड",
|
||||
"JavaScript license information": "जावास्क्रिप्ट लाइसेंस की जानकारी",
|
||||
"source": "स्रोत",
|
||||
"Log in": "लॉग-इन करें",
|
||||
"User ID": "सदस्य ID",
|
||||
"Password": "पासवर्ड",
|
||||
"Register": "पंजीकृत करें",
|
||||
"E-mail": "ईमेल",
|
||||
"Time (h:mm:ss):": "समय (घं:मिमि:सेसे):",
|
||||
"Text CAPTCHA": "टेक्स्ट CAPTCHA",
|
||||
"Image CAPTCHA": "चित्र CAPTCHA",
|
||||
"Sign In": "साइन इन करें",
|
||||
"Preferences": "प्राथमिकताएँ",
|
||||
"preferences_category_player": "प्लेयर की प्राथमिकताएँ",
|
||||
"preferences_video_loop_label": "हमेशा लूप करें: ",
|
||||
"preferences_continue_label": "डिफ़ॉल्ट से अगला चलाएँ: ",
|
||||
"preferences_continue_autoplay_label": "अगला वीडियो अपने आप चलाएँ: ",
|
||||
"preferences_listen_label": "डिफ़ॉल्ट से सुनें: ",
|
||||
"preferences_local_label": "प्रॉक्सी वीडियो: ",
|
||||
"preferences_watch_history_label": "देखने का इतिहास सक्षम करें: ",
|
||||
"preferences_speed_label": "वीडियो चलाने की डिफ़ॉल्ट रफ़्तार: ",
|
||||
"preferences_quality_label": "वीडियो की प्राथमिक क्वालिटी: ",
|
||||
"preferences_quality_option_dash": "DASH (अनुकूली गुणवत्ता)",
|
||||
"preferences_quality_option_hd720": "HD720",
|
||||
"preferences_quality_option_medium": "मध्यम",
|
||||
"preferences_quality_option_small": "छोटा",
|
||||
"preferences_quality_dash_label": "प्राथमिक DASH वीडियो क्वालिटी: ",
|
||||
"preferences_quality_dash_option_720p": "720p",
|
||||
"preferences_quality_dash_option_auto": "अपने-आप",
|
||||
"preferences_quality_dash_option_best": "सबसे अच्छा",
|
||||
"preferences_quality_dash_option_worst": "सबसे खराब",
|
||||
"preferences_quality_dash_option_4320p": "4320p",
|
||||
"preferences_quality_dash_option_2160p": "2160p",
|
||||
"preferences_quality_dash_option_1440p": "1440p",
|
||||
"preferences_quality_dash_option_1080p": "1080p",
|
||||
"preferences_quality_dash_option_480p": "480p",
|
||||
"preferences_quality_dash_option_360p": "360p",
|
||||
"preferences_quality_dash_option_240p": "240p",
|
||||
"preferences_quality_dash_option_144p": "144p",
|
||||
"preferences_comments_label": "डिफ़ॉल्ट टिप्पणियाँ: ",
|
||||
"preferences_volume_label": "प्लेयर का वॉल्यूम: ",
|
||||
"youtube": "YouTube",
|
||||
"reddit": "Reddit",
|
||||
"invidious": "Invidious",
|
||||
"preferences_captions_label": "डिफ़ॉल्ट कैप्शन: ",
|
||||
"Fallback captions: ": "वैकल्पिक कैप्शन: ",
|
||||
"preferences_related_videos_label": "संबंधित वीडियो दिखाएँ: ",
|
||||
"preferences_annotations_label": "डिफ़ॉल्ट से टिप्पणियाँ दिखाएँ: ",
|
||||
"preferences_extend_desc_label": "अपने आप वीडियो के विवरण का विस्तार करें: ",
|
||||
"preferences_vr_mode_label": "उत्तरदायी 360 डिग्री वीडियो (WebGL की ज़रूरत है): ",
|
||||
"preferences_category_visual": "यथादृश्य प्राथमिकताएँ",
|
||||
"preferences_region_label": "सामग्री का राष्ट्र: ",
|
||||
"preferences_player_style_label": "प्लेयर का स्टाइल: ",
|
||||
"Dark mode: ": "डार्क मोड: ",
|
||||
"dark": "डार्क",
|
||||
"light": "लाइट",
|
||||
"preferences_thin_mode_label": "हल्का मोड: ",
|
||||
"preferences_category_misc": "विविध प्राथमिकताएँ",
|
||||
"preferences_automatic_instance_redirect_label": "अपने आप अनुप्रेषित करें (redirect.invidious.io पर फ़ॉलबैक करें): ",
|
||||
"preferences_category_subscription": "सदस्यताओं की प्राथमिकताएँ",
|
||||
"preferences_annotations_subscribed_label": "सदस्यता लिए गए चैनलों पर डिफ़ॉल्ट से टिप्पणियाँ दिखाएँ? ",
|
||||
"Redirect homepage to feed: ": "फ़ीड पर मुखपृष्ठ को अनुप्रेषित करें: ",
|
||||
"preferences_max_results_label": "फ़ीड में दिखाए जाने वाले वीडियों की संख्या: ",
|
||||
"preferences_sort_label": "वीडियों को इस मानदंड पर छाँटें: ",
|
||||
"published": "प्रकाशित",
|
||||
"published - reverse": "प्रकाशित - उल्टा",
|
||||
"Only show latest video from channel: ": "चैनल से सिर्फ नवीनतम वीडियो ही दिखाएँ: ",
|
||||
"alphabetically": "वर्णक्रमानुसार",
|
||||
"Only show latest unwatched video from channel: ": "चैनल से सिर्फ न देखा गया नवीनतम वीडियो ही दिखाएँ: ",
|
||||
"alphabetically - reverse": "वर्णक्रमानुसार - उल्टा",
|
||||
"channel name": "चैनल का नाम",
|
||||
"channel name - reverse": "चैनल का नाम - उल्टा",
|
||||
"preferences_unseen_only_label": "सिर्फ न देखे गए वीडियो ही दिखाएँ: ",
|
||||
"preferences_notifications_only_label": "सिर्फ सूचनाएँ दिखाएँ (अगर हो तो): ",
|
||||
"Enable web notifications": "वेब सूचनाएँ सक्षम करें",
|
||||
"`x` uploaded a video": "`x` ने वीडियो अपलोड किया",
|
||||
"`x` is live": "`x` लाइव हैं",
|
||||
"preferences_category_data": "डेटा की प्राथमिकताएँ",
|
||||
"Clear watch history": "देखने का इतिहास साफ़ करें",
|
||||
"Import/export data": "डेटा को आयात/निर्यात करें",
|
||||
"Change password": "पासवर्ड बदलें",
|
||||
"Manage subscriptions": "सदस्यताएँ प्रबंधित करें",
|
||||
"Manage tokens": "टोकन प्रबंधित करें",
|
||||
"Watch history": "देखने का इतिहास",
|
||||
"Delete account": "खाता हटाएँ",
|
||||
"preferences_category_admin": "प्रबंधक प्राथमिकताएँ",
|
||||
"preferences_feed_menu_label": "फ़ीड मेन्यू: ",
|
||||
"preferences_show_nick_label": "ऊपर उपनाम दिखाएँ: ",
|
||||
"Top enabled: ": "ऊपर का हिस्सा सक्षम है: ",
|
||||
"CAPTCHA enabled: ": "CAPTCHA सक्षम है: ",
|
||||
"Login enabled: ": "लॉग-इन सक्षम है: ",
|
||||
"Registration enabled: ": "पंजीकरण सक्षम है: ",
|
||||
"Report statistics: ": "सांख्यिकी रिपोर्ट करें: ",
|
||||
"Released under the AGPLv3 on Github.": "GitHub पर AGPLv3 के अंतर्गत प्रकाशित।",
|
||||
"Save preferences": "प्राथमिकताएँ सहेजें",
|
||||
"Token manager": "टोकन प्रबंधन",
|
||||
"Token": "टोकन",
|
||||
"tokens_count": "{{count}} टोकन",
|
||||
"tokens_count_plural": "{{count}} टोकन",
|
||||
"Import/export": "आयात/निर्यात करें",
|
||||
"unsubscribe": "सदस्यता छोड़ें",
|
||||
"revoke": "हटाएँ",
|
||||
"Subscriptions": "सदस्यताएँ",
|
||||
"subscriptions_unseen_notifs_count": "{{count}} अपठित सूचना",
|
||||
"subscriptions_unseen_notifs_count_plural": "{{count}} अपठित सूचना",
|
||||
"search": "खोजें",
|
||||
"Log out": "लॉग-आउट करें",
|
||||
"Source available here.": "स्रोत यहाँ उपलब्ध है।",
|
||||
"View JavaScript license information.": "जावास्क्रिप्ट लाइसेंस की जानकारी देखें।",
|
||||
"View privacy policy.": "निजता नीति देखें।",
|
||||
"Trending": "रुझान में",
|
||||
"Public": "सार्वजनिक",
|
||||
"Unlisted": "सबके लिए उपलब्ध नहीं",
|
||||
"Private": "निजी",
|
||||
"View all playlists": "सभी प्लेलिस्ट देखें",
|
||||
"Create playlist": "प्लेलिस्ट बनाएँ",
|
||||
"Updated `x` ago": "`x` पहले अपडेट किया गया",
|
||||
"Delete playlist `x`?": "प्लेलिस्ट `x` हटाएँ?",
|
||||
"Delete playlist": "प्लेलिस्ट हटाएँ",
|
||||
"Title": "शीर्षक",
|
||||
"Playlist privacy": "प्लेलिस्ट की निजता",
|
||||
"Editing playlist `x`": "प्लेलिस्ट `x` को संपादित किया जा रहा है",
|
||||
"Show more": "अधिक देखें",
|
||||
"Show less": "कम देखें",
|
||||
"Watch on YouTube": "YouTube पर देखें",
|
||||
"Switch Invidious Instance": "Invidious उदाहरण बदलें",
|
||||
"search_message_no_results": "कोई परिणाम नहीं मिला।",
|
||||
"search_message_change_filters_or_query": "अपने खोज क्वेरी को और चौड़ा करें और/या फ़िल्टर बदलें।",
|
||||
"search_message_use_another_instance": " आप <a href=\"`x`\">दूसरे उदाहरण पर भी खोज सकते हैं</a>।",
|
||||
"Hide annotations": "टिप्पणियाँ छिपाएँ",
|
||||
"Show annotations": "टिप्पणियाँ दिखाएँ",
|
||||
"Genre: ": "श्रेणी: ",
|
||||
"Family friendly? ": "परिवार के लिए ठीक है? ",
|
||||
"Engagement: ": "सगाई: ",
|
||||
"Whitelisted regions: ": "स्वीकृत क्षेत्र: ",
|
||||
"Blacklisted regions: ": "अस्वीकृत क्षेत्र: ",
|
||||
"Shared `x`": "`x` बाँटा गया",
|
||||
"Premieres in `x`": "`x` बाद प्रीमियर होगा",
|
||||
"Premieres `x`": "`x` को प्रीमिर होगा",
|
||||
"Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "नमस्कार! ऐसा लगता है कि आपका जावास्क्रिप्ट अक्षम है। टिप्पणियाँ देखने के लिए यहाँ क्लिक करें, लेकिन याद रखें कि इन्हें लोड होने में थोड़ा ज़्यादा समय लग सकता है।",
|
||||
"View YouTube comments": "YouTube टिप्पणियाँ देखें",
|
||||
"View more comments on Reddit": "Reddit पर अधिक टिप्पणियाँ देखें",
|
||||
"View `x` comments": {
|
||||
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` टिप्पणी देखें",
|
||||
"": "`x` टिप्पणियाँ देखें"
|
||||
},
|
||||
"View Reddit comments": "Reddit पर टिप्पणियाँ",
|
||||
"Hide replies": "जवाब छिपाएँ",
|
||||
"Show replies": "जवाब दिखाएँ",
|
||||
"Incorrect password": "गलत पासवर्ड",
|
||||
"CAPTCHA is a required field": "CAPTCHA एक ज़रूरी फ़ील्ड है",
|
||||
"User ID is a required field": "सदस्य ID एक ज़रूरी फ़ील्ड है",
|
||||
"Password is a required field": "पासवर्ड एक ज़रूरी फ़ील्ड है",
|
||||
"Wrong username or password": "गलत सदस्यनाम या पासवर्ड",
|
||||
"Password cannot be empty": "पासवर्ड खाली नहीं हो सकता",
|
||||
"Password cannot be longer than 55 characters": "पासवर्ड में अधिकतम 55 अक्षर हो सकते हैं",
|
||||
"Invidious Private Feed for `x`": "`x` के लिए Invidious निजी फ़ीड",
|
||||
"channel:`x`": "चैनल:`x`",
|
||||
"Deleted or invalid channel": "हटाया गया या अमान्य चैनल",
|
||||
"This channel does not exist.": "यह चैनल मौजूद नहीं है।",
|
||||
"Could not get channel info.": "चैनल की जानकारी प्राप्त न की जा सकी।",
|
||||
"comments_view_x_replies": "{{count}} टिप्पणी देखें",
|
||||
"comments_view_x_replies_plural": "{{count}} टिप्पणियाँ देखें",
|
||||
"`x` ago": "`x` पहले",
|
||||
"Load more": "अधिक लोड करें",
|
||||
"Could not create mix.": "मिक्स न बनाया जा सका।",
|
||||
"Empty playlist": "खाली प्लेलिस्ट",
|
||||
"Not a playlist.": "यह प्लेलिस्ट नहीं है।",
|
||||
"Playlist does not exist.": "प्लेलिस्ट मौजूद नहीं है।",
|
||||
"Could not pull trending pages.": "रुझान के पृष्ठ प्राप्त न किए जा सके।",
|
||||
"Hidden field \"challenge\" is a required field": "छिपाया गया फ़ील्ड \"चुनौती\" एक आवश्यक फ़ील्ड है",
|
||||
"Hidden field \"token\" is a required field": "छिपाया गया फ़ील्ड \"टोकन\" एक आवश्यक फ़ील्ड है",
|
||||
"Erroneous challenge": "त्रुटिपूर्ण चुनौती",
|
||||
"Erroneous token": "त्रुटिपूर्ण टोकन",
|
||||
"No such user": "यह सदस्य मौजूद नहीं हैं",
|
||||
"Token is expired, please try again": "टोकन की समय-सीमा समाप्त हो चुकी है, कृपया दोबारा कोशिश करें",
|
||||
"English": "अंग्रेज़ी",
|
||||
"English (United Kingdom)": "अंग्रेज़ी (यूनाइटेड किंग्डम)",
|
||||
"English (United States)": "अंग्रेज़ी (संयुक्त राष्ट्र)",
|
||||
"English (auto-generated)": "अंग्रेज़ी (अपने-आप जनरेट हुआ)",
|
||||
"Afrikaans": "अफ़्रीकी",
|
||||
"Albanian": "अल्बानियाई",
|
||||
"Amharic": "अम्हेरी",
|
||||
"Arabic": "अरबी",
|
||||
"Armenian": "आर्मेनियाई",
|
||||
"Belarusian": "बेलारूसी",
|
||||
"Azerbaijani": "अज़रबैजानी",
|
||||
"Bangla": "बंगाली",
|
||||
"Basque": "बास्क",
|
||||
"Cantonese (Hong Kong)": "कैंटोनीज़ (हाँग काँग)",
|
||||
"Catalan": "कातालान",
|
||||
"Cebuano": "सेबुआनो",
|
||||
"Chinese": "चीनी",
|
||||
"Chinese (China)": "चीनी (चीन)",
|
||||
"Chinese (Hong Kong)": "चीनी (हाँग काँग)",
|
||||
"Chinese (Simplified)": "चीनी (सरलीकृत)",
|
||||
"Chinese (Taiwan)": "चीनी (ताइवान)",
|
||||
"Corsican": "कोर्सिकन",
|
||||
"Croatian": "क्रोएशियाई",
|
||||
"Czech": "चेक",
|
||||
"Danish": "डेनिश",
|
||||
"Dutch": "डच",
|
||||
"Dutch (auto-generated)": "डच (अपने-आप जनरेट हुआ)",
|
||||
"Esperanto": "एस्पेरांतो",
|
||||
"Estonian": "एस्टोनियाई",
|
||||
"Filipino": "फ़िलिपीनो",
|
||||
"Finnish": "फ़िनिश",
|
||||
"French": "फ़्रेंच",
|
||||
"French (auto-generated)": "फ़्रेंच (अपने-आप जनरेट हुआ)",
|
||||
"Galician": "गैलिशियन",
|
||||
"Georgian": "जॉर्जियाई",
|
||||
"German": "जर्मन",
|
||||
"German (auto-generated)": "जर्मन (अपने-आप जनरेट हुआ)",
|
||||
"Greek": "यूनानी",
|
||||
"Gujarati": "गुजराती",
|
||||
"Haitian Creole": "हैती क्रियोल",
|
||||
"Hausa": "हौसा",
|
||||
"Hawaiian": "हवाई",
|
||||
"Hebrew": "हीब्रू",
|
||||
"Hindi": "हिन्दी",
|
||||
"Hmong": "हमोंग",
|
||||
"Hungarian": "हंगेरी",
|
||||
"Icelandic": "आइसलैंडिक",
|
||||
"Igbo": "इग्बो",
|
||||
"Indonesian": "इंडोनेशियाई",
|
||||
"Indonesian (auto-generated)": "इंडोनेशियाई (अपने-आप जनरेट हुआ)",
|
||||
"Interlingue": "इंटरलिंगुआ",
|
||||
"Irish": "आयरिश",
|
||||
"Italian": "इतालवी",
|
||||
"Italian (auto-generated)": "इतालवी (अपने-आप जनरेट हुआ)",
|
||||
"Japanese": "जापानी",
|
||||
"Japanese (auto-generated)": "जापानी (अपने-आप जनरेट हुआ)",
|
||||
"Javanese": "जावानीज़",
|
||||
"Kannada": "कन्नड़",
|
||||
"Kazakh": "कज़ाख़",
|
||||
"Khmer": "खमेर",
|
||||
"Korean": "कोरियाई",
|
||||
"Korean (auto-generated)": "कोरियाई (अपने-आप जनरेट हुआ)",
|
||||
"Kyrgyz": "किर्गीज़",
|
||||
"Lao": "लाओ",
|
||||
"Latin": "लैटिन",
|
||||
"Latvian": "लातवियाई",
|
||||
"Lithuanian": "लिथुएनियाई",
|
||||
"Luxembourgish": "लग्ज़मबर्गी",
|
||||
"Macedonian": "मकादूनियाई",
|
||||
"Malagasy": "मालागासी",
|
||||
"Malay": "मलय",
|
||||
"Malayalam": "मलयालम",
|
||||
"Maltese": "माल्टीज़",
|
||||
"Maori": "माओरी",
|
||||
"Marathi": "मराठी",
|
||||
"Mongolian": "मंगोलियाई",
|
||||
"Nepali": "नेपाली",
|
||||
"Norwegian Bokmål": "नॉर्वेजियाई",
|
||||
"Nyanja": "न्यानजा",
|
||||
"Pashto": "पश्तो",
|
||||
"Persian": "फ़ारसी",
|
||||
"Polish": "पोलिश",
|
||||
"Portuguese": "पुर्तगाली",
|
||||
"Portuguese (auto-generated)": "पुर्तगाली (अपने-आप जनरेट हुआ)",
|
||||
"Portuguese (Brazil)": "पुर्तगाली (ब्राज़ील)",
|
||||
"Romanian": "रोमेनियाई",
|
||||
"Russian": "रूसी",
|
||||
"Russian (auto-generated)": "रूसी (अपने-आप जनरेट हुआ)",
|
||||
"Samoan": "सामोन",
|
||||
"Scottish Gaelic": "स्कॉटिश गाएलिक",
|
||||
"Serbian": "सर्बियाई",
|
||||
"Shona": "शोणा",
|
||||
"Sindhi": "सिंधी",
|
||||
"Slovenian": "स्लोवेनियाई",
|
||||
"Somali": "सोमाली",
|
||||
"Southern Sotho": "दक्षिणी सोथो",
|
||||
"Spanish": "स्पेनी",
|
||||
"Spanish (auto-generated)": "स्पेनी (अपने-आप जनरेट हुआ)",
|
||||
"Spanish (Latin America)": "स्पेनी (लातिन अमेरिकी)",
|
||||
"Spanish (Mexico)": "स्पेनी (मेक्सिको)",
|
||||
"Spanish (Spain)": "स्पेनी (स्पेन)",
|
||||
"Sundanese": "सुंडानी",
|
||||
"Swahili": "स्वाहिली",
|
||||
"Swedish": "स्वीडिश",
|
||||
"Tajik": "ताजीक",
|
||||
"Tamil": "तमिल",
|
||||
"Telugu": "तेलुगु",
|
||||
"Thai": "थाई",
|
||||
"Turkish": "तुर्की",
|
||||
"Turkish (auto-generated)": "तुर्की (अपने-आप जनरेट हुआ)",
|
||||
"Ukrainian": "यूक्रेनी",
|
||||
"Urdu": "उर्दू",
|
||||
"Uzbek": "उज़्बेक",
|
||||
"Vietnamese": "वियतनामी",
|
||||
"Vietnamese (auto-generated)": "वियतनामी (अपने-आप जनरेट हुआ)",
|
||||
"Welsh": "Welsh",
|
||||
"Western Frisian": "पश्चिमी फ़्रिसियाई",
|
||||
"Xhosa": "खोसा",
|
||||
"Yiddish": "यहूदी",
|
||||
"generic_count_years": "{{count}} वर्ष",
|
||||
"generic_count_years_plural": "{{count}} वर्ष",
|
||||
"Yoruba": "योरुबा",
|
||||
"generic_count_months": "{{count}} महीने",
|
||||
"generic_count_months_plural": "{{count}} महीने",
|
||||
"Zulu": "ज़ूलू",
|
||||
"generic_count_weeks": "{{count}} हफ़्ते",
|
||||
"generic_count_weeks_plural": "{{count}} हफ़्ते",
|
||||
"Fallback comments: ": "फ़ॉलबैक टिप्पणियाँ: ",
|
||||
"Popular": "प्रसिद्ध",
|
||||
"Search": "खोजें",
|
||||
"Top": "ऊपर",
|
||||
"About": "जानकारी",
|
||||
"Rating: ": "रेटिंग: ",
|
||||
"preferences_locale_label": "भाषा: ",
|
||||
"View as playlist": "प्लेलिस्ट के रूप में देखें",
|
||||
"Default": "डिफ़ॉल्ट",
|
||||
"Download": "डाउनलोड करें",
|
||||
"Download as: ": "इस रूप में डाउनलोड करें: ",
|
||||
"%A %B %-d, %Y": "%A %B %-d, %Y",
|
||||
"Music": "संगीत",
|
||||
"Gaming": "गेमिंग",
|
||||
"News": "समाचार",
|
||||
"Movies": "फ़िल्में",
|
||||
"(edited)": "(संपादित)",
|
||||
"YouTube comment permalink": "YouTube पर टिप्पणी की स्थायी कड़ी",
|
||||
"permalink": "स्थायी कड़ी",
|
||||
"channel_tab_videos_label": "वीडियो",
|
||||
"`x` marked it with a ❤": "`x` ने इसे एक ❤ से चिह्नित किया",
|
||||
"Audio mode": "ऑडियो मोड",
|
||||
"Playlists": "प्लेलिस्ट्स",
|
||||
"Video mode": "वीडियो मोड",
|
||||
"channel_tab_community_label": "समुदाय",
|
||||
"search_filters_title": "फ़िल्टर",
|
||||
"search_filters_date_label": "अपलोड करने का समय",
|
||||
"search_filters_date_option_none": "कोई भी समय",
|
||||
"search_filters_date_option_week": "इस हफ़्ते",
|
||||
"search_filters_date_option_month": "इस महीने",
|
||||
"search_filters_date_option_hour": "पिछला घंटा",
|
||||
"search_filters_date_option_today": "आज",
|
||||
"search_filters_date_option_year": "इस साल",
|
||||
"search_filters_type_label": "प्रकार",
|
||||
"search_filters_type_option_all": "कोई भी प्रकार",
|
||||
"search_filters_type_option_video": "वीडियो",
|
||||
"search_filters_type_option_channel": "चैनल",
|
||||
"search_filters_sort_option_relevance": "प्रासंगिकता",
|
||||
"search_filters_type_option_playlist": "प्लेलिस्ट",
|
||||
"search_filters_type_option_movie": "फ़िल्म",
|
||||
"search_filters_type_option_show": "शो",
|
||||
"search_filters_duration_label": "अवधि",
|
||||
"search_filters_duration_option_none": "कोई भी अवधि",
|
||||
"search_filters_duration_option_short": "4 मिनट से कम",
|
||||
"search_filters_duration_option_medium": "4 से 20 मिनट तक",
|
||||
"search_filters_duration_option_long": "20 मिनट से ज़्यादा",
|
||||
"search_filters_features_label": "सुविधाएँ",
|
||||
"search_filters_features_option_live": "लाइव",
|
||||
"search_filters_sort_option_rating": "रेटिंग",
|
||||
"search_filters_features_option_four_k": "4K",
|
||||
"search_filters_features_option_hd": "HD",
|
||||
"search_filters_features_option_subtitles": "उपशीर्षक/कैप्शन",
|
||||
"search_filters_features_option_c_commons": "क्रिएटिव कॉमन्स",
|
||||
"search_filters_features_option_three_sixty": "360°",
|
||||
"search_filters_features_option_vr180": "VR180",
|
||||
"search_filters_features_option_three_d": "3D",
|
||||
"search_filters_features_option_hdr": "HDR",
|
||||
"search_filters_features_option_location": "जगह",
|
||||
"search_filters_features_option_purchased": "खरीदा गया",
|
||||
"search_filters_sort_label": "इस क्रम से लगाएँ",
|
||||
"search_filters_sort_option_date": "अपलोड की ताऱीख",
|
||||
"search_filters_sort_option_views": "देखे जाने की संख्या",
|
||||
"search_filters_apply_button": "चयनित फ़िल्टर लागू करें",
|
||||
"footer_documentation": "प्रलेख",
|
||||
"footer_source_code": "स्रोत कोड",
|
||||
"footer_original_source_code": "मूल स्रोत कोड",
|
||||
"footer_modfied_source_code": "बदला गया स्रोत कोड",
|
||||
"Current version: ": "वर्तमान संस्करण: ",
|
||||
"next_steps_error_message": "इसके बाद आपके ये आज़माने चाहिए: ",
|
||||
"next_steps_error_message_refresh": "साफ़ करें",
|
||||
"next_steps_error_message_go_to_youtube": "YouTube पर जाएँ",
|
||||
"footer_donate_page": "दान करें",
|
||||
"adminprefs_modified_source_code_url_label": "बदले गए स्रोत कोड के रिपॉज़िटरी का URL",
|
||||
"none": "कुछ नहीं",
|
||||
"videoinfo_started_streaming_x_ago": "`x` पहले स्ट्रीम करना शुरू किया",
|
||||
"videoinfo_watch_on_youTube": "YouTube पर देखें",
|
||||
"Video unavailable": "वीडियो उपलब्ध नहीं है",
|
||||
"preferences_save_player_pos_label": "यहाँ से चलाना शुरू करें: ",
|
||||
"crash_page_you_found_a_bug": "शायद आपको Invidious में कोई बग नज़र आ गया है!",
|
||||
"videoinfo_youTube_embed_link": "एम्बेड करें",
|
||||
"videoinfo_invidious_embed_link": "एम्बेड करने की कड़ी",
|
||||
"download_subtitles": "उपशीर्षक - `x` (.vtt)",
|
||||
"user_created_playlists": "बनाए गए `x` प्लेलिस्ट्स",
|
||||
"user_saved_playlists": "सहेजे गए `x` प्लेलिस्ट्स",
|
||||
"crash_page_before_reporting": "बग रिपोर्ट करने से पहले:",
|
||||
"crash_page_switch_instance": "<a href=\"`x`\">किसी दूसरे उदाहरण का इस्तेमाल करें</a>",
|
||||
"crash_page_read_the_faq": "<a href=\"`x`\">अक्सर पूछे जाने वाले प्रश्न (FAQ)</a> पढ़ें",
|
||||
"crash_page_refresh": "<a href=\"`x`\">पृष्ठ को एक बार साफ़ करें</a>",
|
||||
"crash_page_search_issue": "<a href=\"`x`\">GitHub पर मौजूदा मुद्दे</a> ढूँढ़ें",
|
||||
"Popular enabled: ": "लोकप्रिय सक्षम: ",
|
||||
"Artist: ": "कलाकार: ",
|
||||
"Music in this video": "इस वीडियो में संगीत",
|
||||
"Album: ": "एल्बम: ",
|
||||
"error_video_not_in_playlist": "अनुरोधित वीडियो इस प्लेलिस्ट में मौजूद नहीं है। <a href=\"`x`\">प्लेलिस्ट के मुखपृष्ठ पर जाने के लिए यहाँ क्लिक करें।</a>",
|
||||
"channel_tab_shorts_label": "शॉर्ट्स",
|
||||
"channel_tab_streams_label": "लाइवस्ट्रीम्स",
|
||||
"channel_tab_playlists_label": "प्लेलिस्ट्स",
|
||||
"channel_tab_channels_label": "चैनल्स"
|
||||
}
|
@ -1 +0,0 @@
|
||||
{}
|
@ -1,123 +0,0 @@
|
||||
{
|
||||
"generic_views_count": "බැලීම් {{count}}",
|
||||
"generic_views_count_plural": "බැලීම් {{count}}",
|
||||
"generic_videos_count": "{{count}} වීඩියෝව",
|
||||
"generic_videos_count_plural": "වීඩියෝ {{count}}",
|
||||
"generic_subscribers_count": "ග්රාහකයන් {{count}}",
|
||||
"generic_subscribers_count_plural": "ග්රාහකයන් {{count}}",
|
||||
"generic_subscriptions_count": "දායකත්ව {{count}}",
|
||||
"generic_subscriptions_count_plural": "දායකත්ව {{count}}",
|
||||
"Shared `x` ago": "`x` පෙර බෙදා ගන්නා ලදී",
|
||||
"Unsubscribe": "දායක නොවන්න",
|
||||
"View playlist on YouTube": "YouTube හි ධාවන ලැයිස්තුව බලන්න",
|
||||
"newest": "අලුත්ම",
|
||||
"oldest": "පැරණිතම",
|
||||
"popular": "ජනප්රිය",
|
||||
"last": "අවසන්",
|
||||
"Authorize token?": "ටෝකනය අනුමත කරනවා ද?",
|
||||
"Authorize token for `x`?": "`x` සඳහා ටෝකනය අනුමත කරනවා ද?",
|
||||
"Yes": "ඔව්",
|
||||
"Import and Export Data": "දත්ත ආනයනය සහ අපනයනය කිරීම",
|
||||
"Import": "ආනයන",
|
||||
"Import Invidious data": "Invidious JSON දත්ත ආයාත කරන්න",
|
||||
"Import FreeTube subscriptions (.db)": "FreeTube දායකත්වයන් (.db) ආයාත කරන්න",
|
||||
"Import NewPipe subscriptions (.json)": "NewPipe දායකත්වයන් (.json) ආයාත කරන්න",
|
||||
"Import NewPipe data (.zip)": "NewPipe දත්ත (.zip) ආයාත කරන්න",
|
||||
"Export": "අපනයන",
|
||||
"Export data as JSON": "Invidious දත්ත JSON ලෙස අපනයනය කරන්න",
|
||||
"Delete account?": "ගිණුම මකාදමනවා ද?",
|
||||
"History": "ඉතිහාසය",
|
||||
"An alternative front-end to YouTube": "YouTube සඳහා විකල්ප ඉදිරිපස අන්තයක්",
|
||||
"source": "මූලාශ්රය",
|
||||
"Log in/register": "පුරන්න/ලියාපදිංචිවන්න",
|
||||
"Password": "මුරපදය",
|
||||
"Time (h:mm:ss):": "වේලාව (h:mm:ss):",
|
||||
"Sign In": "පුරන්න",
|
||||
"Preferences": "මනාපයන්",
|
||||
"preferences_category_player": "වීඩියෝ ධාවක මනාපයන්",
|
||||
"preferences_video_loop_label": "නැවත නැවතත්: ",
|
||||
"preferences_autoplay_label": "ස්වයංක්රීය වාදනය: ",
|
||||
"preferences_continue_label": "මීලඟට වාදනය කරන්න: ",
|
||||
"preferences_continue_autoplay_label": "මීළඟ වීඩියෝව ස්වයංක්රීයව ධාවනය කරන්න: ",
|
||||
"preferences_local_label": "Proxy වීඩියෝ: ",
|
||||
"preferences_watch_history_label": "නැරඹුම් ඉතිහාසය සබල කරන්න: ",
|
||||
"preferences_speed_label": "පෙරනිමි වේගය: ",
|
||||
"preferences_quality_option_dash": "DASH (අනුවර්තිත ගුණත්වය)",
|
||||
"preferences_quality_option_medium": "මධ්යස්ථ",
|
||||
"preferences_quality_dash_label": "කැමති DASH වීඩියෝ ගුණත්වය: ",
|
||||
"preferences_quality_dash_option_4320p": "4320p",
|
||||
"preferences_quality_dash_option_1080p": "1080p",
|
||||
"preferences_quality_dash_option_480p": "480p",
|
||||
"preferences_quality_dash_option_360p": "360p",
|
||||
"preferences_quality_dash_option_144p": "144p",
|
||||
"preferences_volume_label": "ධාවකයේ හඬ: ",
|
||||
"preferences_comments_label": "පෙරනිමි අදහස්: ",
|
||||
"youtube": "YouTube",
|
||||
"reddit": "Reddit",
|
||||
"invidious": "Invidious",
|
||||
"preferences_captions_label": "පෙරනිමි උපසිරැසි: ",
|
||||
"preferences_related_videos_label": "අදාළ වීඩියෝ පෙන්වන්න: ",
|
||||
"preferences_annotations_label": "අනුසටහන් පෙන්වන්න: ",
|
||||
"preferences_vr_mode_label": "අන්තර්ක්රියාකාරී අංශක 360 වීඩියෝ (WebGL අවශ්යයි): ",
|
||||
"preferences_region_label": "අන්තර්ගත රට: ",
|
||||
"preferences_player_style_label": "වීඩියෝ ධාවක විලාසය: ",
|
||||
"Dark mode: ": "අඳුරු මාදිලිය: ",
|
||||
"preferences_dark_mode_label": "තේමාව: ",
|
||||
"light": "ආලෝකමත්",
|
||||
"generic_playlists_count": "{{count}} ධාවන ලැයිස්තුව",
|
||||
"generic_playlists_count_plural": "ධාවන ලැයිස්තු {{count}}",
|
||||
"LIVE": "සජීව",
|
||||
"Subscribe": "දායක වන්න",
|
||||
"View channel on YouTube": "YouTube හි නාලිකාව බලන්න",
|
||||
"Next page": "ඊළඟ පිටුව",
|
||||
"Previous page": "පෙර පිටුව",
|
||||
"Clear watch history?": "නැරඹුම් ඉතිහාසය මකාදමනවා ද?",
|
||||
"No": "නැත",
|
||||
"Log in": "පුරන්න",
|
||||
"New password": "නව මුරපදය",
|
||||
"Import YouTube subscriptions": "YouTube/OPML දායකත්වයන් ආයාත කරන්න",
|
||||
"Register": "ලියාපදිංචිවන්න",
|
||||
"New passwords must match": "නව මුරපද ගැලපිය යුතුය",
|
||||
"Export subscriptions as OPML (for NewPipe & FreeTube)": "OPML ලෙස දායකත්වයන් අපනයනය කරන්න (NewPipe සහ FreeTube සඳහා)",
|
||||
"Export subscriptions as OPML": "දායකත්වයන් OPML ලෙස අපනයනය කරන්න",
|
||||
"JavaScript license information": "JavaScript බලපත්ර තොරතුරු",
|
||||
"User ID": "පරිශීලක කේතය",
|
||||
"Text CAPTCHA": "CAPTCHA පෙල",
|
||||
"Image CAPTCHA": "CAPTCHA රූපය",
|
||||
"E-mail": "විද්යුත් තැපෑල",
|
||||
"preferences_quality_label": "කැමති වීඩියෝ ගුණත්වය: ",
|
||||
"preferences_quality_option_hd720": "HD720",
|
||||
"preferences_quality_dash_option_auto": "ස්වයංක්රීය",
|
||||
"preferences_quality_option_small": "කුඩා",
|
||||
"preferences_quality_dash_option_best": "උසස්",
|
||||
"preferences_quality_dash_option_2160p": "2160p",
|
||||
"preferences_quality_dash_option_1440p": "1440p",
|
||||
"preferences_quality_dash_option_720p": "720p",
|
||||
"preferences_quality_dash_option_240p": "240p",
|
||||
"preferences_extend_desc_label": "වීඩියෝ විස්තරය ස්වයංක්රීයව දිගහරින්න: ",
|
||||
"preferences_category_visual": "දෘශ්ය මනාපයන්",
|
||||
"dark": "අඳුරු",
|
||||
"preferences_category_misc": "විවිධ මනාප",
|
||||
"preferences_category_subscription": "දායකත්ව මනාප",
|
||||
"Redirect homepage to feed: ": "මුල් පිටුව පෝෂණය වෙත හරවා යවන්න: ",
|
||||
"preferences_max_results_label": "සංග්රහයේ පෙන්වන වීඩියෝ ගණන: ",
|
||||
"preferences_sort_label": "වීඩියෝ වර්ග කරන්න: ",
|
||||
"alphabetically": "අකාරාදී ලෙස",
|
||||
"alphabetically - reverse": "අකාරාදී - ආපසු",
|
||||
"channel name": "නාලිකාවේ නම",
|
||||
"Only show latest video from channel: ": "නාලිකාවේ නවතම වීඩියෝව පමණක් පෙන්වන්න: ",
|
||||
"preferences_unseen_only_label": "නොබැලූ පමණක් පෙන්වන්න: ",
|
||||
"Enable web notifications": "වෙබ් දැනුම්දීම් සබල කරන්න",
|
||||
"Import/export data": "දත්ත ආනයනය / අපනයනය",
|
||||
"Change password": "මුරපදය වෙනස් කරන්න",
|
||||
"Manage subscriptions": "දායකත්ව කළමනාකරණය",
|
||||
"Manage tokens": "ටෝකන කළමනාකරණය",
|
||||
"Watch history": "නැරඹුම් ඉතිහාසය",
|
||||
"Save preferences": "මනාප සුරකින්න",
|
||||
"Token": "ටෝකනය",
|
||||
"View privacy policy.": "රහස්යතා ප්රතිපත්තිය බලන්න.",
|
||||
"Only show latest unwatched video from channel: ": "නාලිකාවේ නවතම නැරඹන නොලද වීඩියෝව පමණක් පෙන්වන්න: ",
|
||||
"preferences_category_data": "දත්ත මනාප",
|
||||
"Clear watch history": "නැරඹුම් ඉතිහාසය මකාදැමීම",
|
||||
"Subscriptions": "දායකත්ව"
|
||||
}
|
@ -1,511 +0,0 @@
|
||||
{
|
||||
"No": "Ne",
|
||||
"Subscribe": "Naroči se",
|
||||
"View playlist on YouTube": "Ogled seznama predvajanja v YouTubu",
|
||||
"last": "zadnji",
|
||||
"Next page": "Naslednja stran",
|
||||
"Previous page": "Prejšnja stran",
|
||||
"Clear watch history?": "Izbrisati zgodovino ogledov?",
|
||||
"New password": "Novo geslo",
|
||||
"New passwords must match": "Nova gesla se morajo ujemati",
|
||||
"Authorize token?": "Naj odobrim žeton?",
|
||||
"Yes": "Da",
|
||||
"Import and Export Data": "Uvoz in izvoz podatkov",
|
||||
"Import": "Uvozi",
|
||||
"Import Invidious data": "Uvozi Invidious JSON podatke",
|
||||
"Import YouTube subscriptions": "Uvozi YouTube/OPML naročnine",
|
||||
"Import FreeTube subscriptions (.db)": "Uvozi FreeTube (.db) naročnine",
|
||||
"Import NewPipe data (.zip)": "Uvozi NewPipe (.zip) podatke",
|
||||
"Export": "Izvozi",
|
||||
"Export subscriptions as OPML": "Izvozi naročnine kot OPML",
|
||||
"Export subscriptions as OPML (for NewPipe & FreeTube)": "Izvozi naročnine kot OPML (za NewPipe in FreeTube)",
|
||||
"Log in": "Prijava",
|
||||
"Log in/register": "Prijava/registracija",
|
||||
"User ID": "ID uporabnika",
|
||||
"Password": "Geslo",
|
||||
"Time (h:mm:ss):": "Čas (h:mm:ss):",
|
||||
"Text CAPTCHA": "Besedilo CAPTCHA",
|
||||
"source": "izvorna koda",
|
||||
"Image CAPTCHA": "Slika CAPTCHA",
|
||||
"Sign In": "Prijavi se",
|
||||
"Register": "Registriraj se",
|
||||
"E-mail": "E-pošta",
|
||||
"Preferences": "Nastavitve",
|
||||
"preferences_video_loop_label": "Vedno v zanki: ",
|
||||
"preferences_autoplay_label": "Samodejno predvajanje: ",
|
||||
"preferences_continue_autoplay_label": "Samodejno predvajanje naslednjega videoposnetka: ",
|
||||
"preferences_listen_label": "Privzeto poslušaj: ",
|
||||
"preferences_local_label": "Proxy za videoposnetke: ",
|
||||
"preferences_speed_label": "Privzeta hitrost: ",
|
||||
"preferences_quality_label": "Prednostna kakovost videoposnetka: ",
|
||||
"preferences_quality_option_hd720": "HD720",
|
||||
"preferences_quality_dash_option_best": "najboljša",
|
||||
"preferences_quality_dash_option_4320p": "4320p",
|
||||
"preferences_quality_dash_option_1440p": "1440p",
|
||||
"preferences_quality_dash_option_1080p": "1080p",
|
||||
"preferences_quality_dash_option_720p": "720p",
|
||||
"preferences_quality_dash_option_480p": "480p",
|
||||
"preferences_quality_dash_option_360p": "360p",
|
||||
"preferences_quality_dash_option_240p": "240p",
|
||||
"preferences_volume_label": "Glasnost predvajalnika: ",
|
||||
"reddit": "Reddit",
|
||||
"preferences_player_style_label": "Slog predvajalnika: ",
|
||||
"dark": "temna",
|
||||
"light": "svetla",
|
||||
"preferences_thin_mode_label": "Tanki način: ",
|
||||
"preferences_automatic_instance_redirect_label": "Samodejna preusmeritev (na redirect.invidious.io): ",
|
||||
"preferences_annotations_subscribed_label": "Privzeto prikazati opombe za naročene kanale? ",
|
||||
"Redirect homepage to feed: ": "Preusmeri domačo stran na vir: ",
|
||||
"preferences_max_results_label": "Število videoposnetkov, prikazanih v viru: ",
|
||||
"preferences_sort_label": "Razvrsti videoposnetke po: ",
|
||||
"published": "datumu objave",
|
||||
"published - reverse": "datumu objave - obratno",
|
||||
"alphabetically": "abecednem vrstnem redu",
|
||||
"alphabetically - reverse": "po abecednem vrstnem redu - obratno",
|
||||
"channel name": "imenu kanala",
|
||||
"channel name - reverse": "imenu kanala - obratno",
|
||||
"Only show latest video from channel: ": "Pokaži samo najnovejši videoposnetek iz kanala: ",
|
||||
"Only show latest unwatched video from channel: ": "Pokaži samo najnovejši še neogledani videoposnetek iz kanala: ",
|
||||
"preferences_unseen_only_label": "Pokaži samo neogledane: ",
|
||||
"preferences_notifications_only_label": "Pokaži samo obvestila (če obstajajo): ",
|
||||
"preferences_category_data": "Nastavitve podatkov",
|
||||
"Clear watch history": "Počisti zgodovino ogledov",
|
||||
"Import/export data": "Uvoz/izvoz podatkov",
|
||||
"Change password": "Spremeni geslo",
|
||||
"Watch history": "Oglej si zgodovino",
|
||||
"Delete account": "Izbriši račun",
|
||||
"preferences_category_admin": "Skrbniške nastavitve",
|
||||
"preferences_default_home_label": "Privzeta domača stran: ",
|
||||
"preferences_feed_menu_label": "Meni vira: ",
|
||||
"Top enabled: ": "Vrh omogočen: ",
|
||||
"CAPTCHA enabled: ": "CAPTCHA omogočeni: ",
|
||||
"Login enabled: ": "Prijava je omogočena: ",
|
||||
"Registration enabled: ": "Registracija je omogočena: ",
|
||||
"Token manager": "Upravitelj žetonov",
|
||||
"Token": "Žeton",
|
||||
"tokens_count_0": "{{count}} žeton",
|
||||
"tokens_count_1": "{{count}} žetona",
|
||||
"tokens_count_2": "{{count}} žetoni",
|
||||
"tokens_count_3": "{{count}} žetonov",
|
||||
"Import/export": "Uvoz/izvoz",
|
||||
"unsubscribe": "odjava",
|
||||
"revoke": "prekliči",
|
||||
"search": "iskanje",
|
||||
"Log out": "Odjava",
|
||||
"Released under the AGPLv3 on Github.": "Objavljeno pod licenco AGPLv3 na GitHubu.",
|
||||
"Trending": "Trendi",
|
||||
"Private": "Zasebno",
|
||||
"View all playlists": "Oglej si vse sezname predvajanja",
|
||||
"Updated `x` ago": "Posodobljeno pred `x`",
|
||||
"Delete playlist `x`?": "Brisanje seznama predvajanja `x`?",
|
||||
"Delete playlist": "Izbriši seznam predvajanja",
|
||||
"Title": "Naslov",
|
||||
"Playlist privacy": "Zasebnost seznama predvajanja",
|
||||
"Editing playlist `x`": "Urejanje seznama predvajanja `x`",
|
||||
"Show more": "Pokaži več",
|
||||
"Switch Invidious Instance": "Preklopi Invidious instanco",
|
||||
"search_message_change_filters_or_query": "Poskusi razširiti iskalno poizvedbo in/ali spremeniti filtre.",
|
||||
"search_message_use_another_instance": " Lahko tudi <a href=\"`x`\">iščeš v drugi istanci</a>.",
|
||||
"Wilson score: ": "Wilsonov rezultat: ",
|
||||
"Engagement: ": "Sodelovanje: ",
|
||||
"Blacklisted regions: ": "Regije na seznamu nedovoljenih: ",
|
||||
"Shared `x`": "V skupni rabi od: `x`",
|
||||
"Premieres `x`": "Premiere `x`",
|
||||
"View YouTube comments": "Oglej si YouTube komentarje",
|
||||
"View more comments on Reddit": "Prikaži več komentarjev na Reddit",
|
||||
"View `x` comments": {
|
||||
"([^.,0-9]|^)1([^.,0-9]|$)": "Poglej `x` komentar",
|
||||
"": "Poglej `x` komentarjev"
|
||||
},
|
||||
"Password cannot be empty": "Geslo ne sme biti prazno",
|
||||
"`x` ago": "`x` nazaj",
|
||||
"Load more": "Naloži več",
|
||||
"comments_points_count_0": "{{count}} točka",
|
||||
"comments_points_count_1": "{{count}} točki",
|
||||
"comments_points_count_2": "{{count}} točke",
|
||||
"comments_points_count_3": "{{count}} točk",
|
||||
"Hidden field \"token\" is a required field": "Skrito polje »žeton« je zahtevano polje",
|
||||
"Erroneous challenge": "Napačen izziv",
|
||||
"English": "angleščina",
|
||||
"English (United States)": "angleščina (Združene države)",
|
||||
"Albanian": "albanščina",
|
||||
"Amharic": "amharščina",
|
||||
"Azerbaijani": "azerbajdžanščina",
|
||||
"Bangla": "bengalščina",
|
||||
"Belarusian": "beloruščina",
|
||||
"Burmese": "birmanščina",
|
||||
"Cebuano": "cebuanščina",
|
||||
"Chinese (Hong Kong)": "kitajščina (Hongkong)",
|
||||
"Chinese (Simplified)": "kitajščina (poenostavljena)",
|
||||
"Chinese (Taiwan)": "kitajščina (Tajvan)",
|
||||
"Corsican": "korzijščina",
|
||||
"Croatian": "hrvaščina",
|
||||
"Danish": "danščina",
|
||||
"Dutch": "nizozemščina",
|
||||
"Estonian": "estonščina",
|
||||
"Filipino": "filipinščina",
|
||||
"Finnish": "finščina",
|
||||
"French": "francoščina",
|
||||
"French (auto-generated)": "francoščina (samodejno ustvarjeno)",
|
||||
"Georgian": "gruzinščina",
|
||||
"German": "nemščina",
|
||||
"Greek": "grščina",
|
||||
"Gujarati": "gudžaratščina",
|
||||
"Haitian Creole": "haitijska kreolščina",
|
||||
"Hausa": "havščina",
|
||||
"Hawaiian": "havajščina",
|
||||
"Hmong": "hmonščina",
|
||||
"Hungarian": "madžarščina",
|
||||
"Icelandic": "islandščina",
|
||||
"Igbo": "igbo",
|
||||
"Interlingue": "interlingua",
|
||||
"Italian (auto-generated)": "italijanščina (samodejno ustvarjeno)",
|
||||
"Japanese": "japonščina",
|
||||
"Japanese (auto-generated)": "japonščina (samodejno ustvarjeno)",
|
||||
"Khmer": "kmerščina",
|
||||
"Korean": "korejščina",
|
||||
"Korean (auto-generated)": "korejščina (samodejno ustvarjeno)",
|
||||
"Kurdish": "kurdščina",
|
||||
"Kannada": "kanadejščina",
|
||||
"Latvian": "latvijščina",
|
||||
"Lithuanian": "litovščina",
|
||||
"Luxembourgish": "luksemburščina",
|
||||
"Macedonian": "makedonščina",
|
||||
"Malagasy": "malgaščina",
|
||||
"Malay": "malajščina",
|
||||
"Nepali": "nepalščina",
|
||||
"Norwegian Bokmål": "norveščina bokmal",
|
||||
"Nyanja": "njanščina",
|
||||
"Punjabi": "pandžabščina",
|
||||
"Romanian": "romunščina",
|
||||
"Russian": "ruščina",
|
||||
"Samoan": "samoanščina",
|
||||
"Scottish Gaelic": "škotska galščina",
|
||||
"Shona": "šonaščina",
|
||||
"Sundanese": "sudanščina",
|
||||
"Thai": "tajščina",
|
||||
"Turkish": "turščina",
|
||||
"Turkish (auto-generated)": "turščina (samodejno ustvarjeno)",
|
||||
"Ukrainian": "ukrajinščina",
|
||||
"Urdu": "urdujščina",
|
||||
"Telugu": "telugu",
|
||||
"Vietnamese": "vietnamščina",
|
||||
"Welsh": "valižanščina",
|
||||
"Western Frisian": "zahodnofrizijščina",
|
||||
"Yiddish": "jidiš",
|
||||
"Yoruba": "joruba",
|
||||
"Xhosa": "xhosa",
|
||||
"generic_count_years_0": "{{count}} letom",
|
||||
"generic_count_years_1": "{{count}} leti",
|
||||
"generic_count_years_2": "{{count}} leti",
|
||||
"generic_count_years_3": "{{count}} leti",
|
||||
"generic_count_days_0": "{{count}} dnevom",
|
||||
"generic_count_days_1": "{{count}} dnevoma",
|
||||
"generic_count_days_2": "{{count}} dnevi",
|
||||
"generic_count_days_3": "{{count}} dnevi",
|
||||
"generic_count_hours_0": "{{count}} uro",
|
||||
"generic_count_hours_1": "{{count}} urami",
|
||||
"generic_count_hours_2": "{{count}} urami",
|
||||
"generic_count_hours_3": "{{count}} urami",
|
||||
"generic_count_minutes_0": "{{count}} minuto",
|
||||
"generic_count_minutes_1": "{{count}} minutami",
|
||||
"generic_count_minutes_2": "{{count}} minutami",
|
||||
"generic_count_minutes_3": "{{count}} minutami",
|
||||
"Search": "Iskanje",
|
||||
"Top": "Vrh",
|
||||
"About": "O aplikaciji",
|
||||
"%A %B %-d, %Y": "%A %-d %B %Y",
|
||||
"Audio mode": "Avdio način",
|
||||
"channel_tab_videos_label": "Videoposnetki",
|
||||
"search_filters_date_label": "Datum nalaganja",
|
||||
"search_filters_date_option_today": "Danes",
|
||||
"search_filters_date_option_week": "Ta teden",
|
||||
"search_filters_type_label": "Vrsta",
|
||||
"search_filters_type_option_all": "Katerakoli vrsta",
|
||||
"search_filters_type_option_playlist": "Seznami predvajanja",
|
||||
"search_filters_features_option_subtitles": "Podnapisi/CC",
|
||||
"search_filters_features_option_location": "Lokacija",
|
||||
"footer_donate_page": "Prispevaj",
|
||||
"footer_documentation": "Dokumentacija",
|
||||
"footer_original_source_code": "Izvirna izvorna koda",
|
||||
"none": "ni",
|
||||
"videoinfo_started_streaming_x_ago": "Začetek pretakanja `x` nazaj",
|
||||
"videoinfo_watch_on_youTube": "Oglej si v YouTubu",
|
||||
"user_saved_playlists": "`x` shranjenih seznamov predvajanja",
|
||||
"Video unavailable": "Video ni na voljo",
|
||||
"preferences_save_player_pos_label": "Shrani položaj predvajanja: ",
|
||||
"crash_page_you_found_a_bug": "Videti je, da si v Invidiousu našel hrošča!",
|
||||
"crash_page_read_the_faq": "prebral/a <a href=\"`x`\">Pogosto zastavljena vprašanja (FAQ)</a>",
|
||||
"generic_videos_count_0": "{{count}} video",
|
||||
"generic_videos_count_1": "{{count}} videa",
|
||||
"generic_videos_count_2": "{{count}} videi",
|
||||
"generic_videos_count_3": "{{count}} videov",
|
||||
"generic_views_count_0": "Ogledov: {{count}}",
|
||||
"generic_views_count_1": "Ogledov: {{count}}",
|
||||
"generic_views_count_2": "Ogledov: {{count}}",
|
||||
"generic_views_count_3": "Ogledov: {{count}}",
|
||||
"generic_playlists_count_0": "{{count}} seznam predvajanja",
|
||||
"generic_playlists_count_1": "{{count}} seznama predvajanja",
|
||||
"generic_playlists_count_2": "{{count}} seznami predvajanja",
|
||||
"generic_playlists_count_3": "{{count}} seznamov predvajanja",
|
||||
"generic_subscribers_count_0": "{{count}} naročnik",
|
||||
"generic_subscribers_count_1": "{{count}} naročnika",
|
||||
"generic_subscribers_count_2": "{{count}} naročniki",
|
||||
"generic_subscribers_count_3": "{{count}} naročnikov",
|
||||
"generic_subscriptions_count_0": "{{count}} naročnina",
|
||||
"generic_subscriptions_count_1": "{{count}} naročnini",
|
||||
"generic_subscriptions_count_2": "{{count}} naročnine",
|
||||
"generic_subscriptions_count_3": "{{count}} naročnin",
|
||||
"LIVE": "V ŽIVO",
|
||||
"Shared `x` ago": "Deljeno pred `x`",
|
||||
"View channel on YouTube": "Ogled kanala v YouTubu",
|
||||
"newest": "najnovejši",
|
||||
"Unsubscribe": "Odjavi se",
|
||||
"Authorize token for `x`?": "Odobriti žeton za `x`?",
|
||||
"Import NewPipe subscriptions (.json)": "Uvozi NewPipe (.json) naročnine",
|
||||
"History": "Zgodovina",
|
||||
"JavaScript license information": "Podatki o licenci JavaScript",
|
||||
"oldest": "najstarejši",
|
||||
"popular": "priljubljen",
|
||||
"Export data as JSON": "Izvozi Invidious podatke kot JSON",
|
||||
"Delete account?": "Izbrisati račun?",
|
||||
"An alternative front-end to YouTube": "Alternativni vmesnik za YouTube",
|
||||
"preferences_category_player": "Nastavitve predvajalnika",
|
||||
"preferences_continue_label": "Privzeto predvajaj naslednjega: ",
|
||||
"preferences_watch_history_label": "Omogoči zgodovino ogledov: ",
|
||||
"preferences_quality_option_medium": "srednja",
|
||||
"preferences_quality_option_dash": "DASH (prilagodljiva kakovost)",
|
||||
"preferences_quality_option_small": "majhna",
|
||||
"preferences_quality_dash_option_worst": "najslabša",
|
||||
"preferences_quality_dash_label": "Prednostna kakovost videoposnetkov DASH: ",
|
||||
"preferences_comments_label": "Privzeti komentarji: ",
|
||||
"preferences_quality_dash_option_auto": "samodejna",
|
||||
"preferences_quality_dash_option_2160p": "2160p",
|
||||
"preferences_quality_dash_option_144p": "144p",
|
||||
"youtube": "YouTube",
|
||||
"invidious": "Invidious",
|
||||
"preferences_vr_mode_label": "Interaktivni videoposnetki na 360 stopinj (zahteva WebGL): ",
|
||||
"preferences_captions_label": "Privzeti napisi: ",
|
||||
"Fallback captions: ": "Pomožni napisi: ",
|
||||
"preferences_extend_desc_label": "Samodejno razširi opis videoposnetka: ",
|
||||
"preferences_related_videos_label": "Prikaži povezane videoposnetke: ",
|
||||
"preferences_annotations_label": "Privzeto prikaži opombe: ",
|
||||
"preferences_category_visual": "Vizualne nastavitve",
|
||||
"preferences_region_label": "Država vsebine: ",
|
||||
"Dark mode: ": "Temni način: ",
|
||||
"preferences_dark_mode_label": "Tema: ",
|
||||
"preferences_category_misc": "Različne nastavitve",
|
||||
"preferences_category_subscription": "Nastavitve naročnine",
|
||||
"Unlisted": "Nerazporejeno",
|
||||
"Enable web notifications": "Omogoči spletna obvestila",
|
||||
"`x` is live": "`x` je v živo",
|
||||
"Manage subscriptions": "Upravljaj naročnine",
|
||||
"Manage tokens": "Upravljaj žetone",
|
||||
"Subscription manager": "Upravitelj naročnin",
|
||||
"`x` uploaded a video": "`x` je naložil/a videoposnetek",
|
||||
"preferences_show_nick_label": "Prikaži vzdevek na vrhu: ",
|
||||
"search_message_no_results": "Ni zadetkov.",
|
||||
"Save preferences": "Shrani nastavitve",
|
||||
"Subscriptions": "Naročnine",
|
||||
"Report statistics: ": "Poročilo o statistiki: ",
|
||||
"subscriptions_unseen_notifs_count_0": "{{count}} neogledano obvestilo",
|
||||
"subscriptions_unseen_notifs_count_1": "{{count}} neogledani obvestili",
|
||||
"subscriptions_unseen_notifs_count_2": "{{count}} neogledana obvestila",
|
||||
"subscriptions_unseen_notifs_count_3": "{{count}} neogledanih obvestil",
|
||||
"View JavaScript license information.": "Oglej si informacije o licenci za JavaScript.",
|
||||
"Show less": "Pokaži manj",
|
||||
"Watch on YouTube": "Oglej si v YouTubu",
|
||||
"Source available here.": "Izvorna koda na voljo tukaj.",
|
||||
"License: ": "Licenca: ",
|
||||
"View privacy policy.": "Oglej si pravilnik o zasebnosti.",
|
||||
"Public": "Javno",
|
||||
"Create playlist": "Ustvari seznam predvajanja",
|
||||
"Hide annotations": "Skrij opombe",
|
||||
"Show annotations": "Pokaži opombe",
|
||||
"Genre: ": "Žanr: ",
|
||||
"Family friendly? ": "Družinam prijazno? ",
|
||||
"Whitelisted regions: ": "Regije na seznamu dovoljenih: ",
|
||||
"Premieres in `x`": "Premiere v `x`",
|
||||
"Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "Živjo! Izgleda, da imaš izklopljene JavaScripte . Klikni tukaj, če si želiš ogledati komentarje, vendar vedi, da bo lahko nalaganje trajajo nekoliko dlje.",
|
||||
"Show replies": "Pokaži odgovore",
|
||||
"Erroneous CAPTCHA": "Napačna CAPTCHA",
|
||||
"User ID is a required field": "ID uporabnika je obvezno polje",
|
||||
"Password is a required field": "Geslo je obvezno polje",
|
||||
"Wrong username or password": "Napačno uporabniško ime ali geslo",
|
||||
"Password cannot be longer than 55 characters": "Geslo ne sme biti daljše od 55 znakov",
|
||||
"channel:`x`": "kanal: `x`",
|
||||
"Could not fetch comments": "Ni bilo mogoče pridobiti komentarjev",
|
||||
"Could not pull trending pages.": "Ni bilo mogoče povleči trendovskih strani.",
|
||||
"Please log in": "Prosim, prijavi se",
|
||||
"Playlist does not exist.": "Seznam predvajanja ne obstaja.",
|
||||
"Incorrect password": "Napačno geslo",
|
||||
"View Reddit comments": "Oglej si komentarje na Redditu",
|
||||
"This channel does not exist.": "Ta kanal ne obstaja.",
|
||||
"Hide replies": "Skrij odgovore",
|
||||
"Invidious Private Feed for `x`": "Invidious zasebni vir za `x`",
|
||||
"Deleted or invalid channel": "Izbrisan ali neveljaven kanal",
|
||||
"Empty playlist": "Prazen seznam predvajanja",
|
||||
"No such user": "Ni tega uporabnika",
|
||||
"Token is expired, please try again": "Žeton je potekel, poskusi znova",
|
||||
"English (United Kingdom)": "angleščina (Združeno kraljestvo)",
|
||||
"Wrong answer": "Napačen odgovor",
|
||||
"CAPTCHA is a required field": "CAPTCHA je obvezno polje",
|
||||
"Could not get channel info.": "Ni bilo mogoče dobiti informacij o kanalu.",
|
||||
"comments_view_x_replies_0": "Poglej {{count}} odgovor",
|
||||
"comments_view_x_replies_1": "Poglej {{count}} odgovora",
|
||||
"comments_view_x_replies_2": "Poglej {{count}} odgovore",
|
||||
"comments_view_x_replies_3": "Poglej {{count}} odgovorov",
|
||||
"Could not create mix.": "Ni bilo mogoče ustvariti mixa.",
|
||||
"Not a playlist.": "Ni seznam predvajanja.",
|
||||
"Hidden field \"challenge\" is a required field": "Skrito polje »izziv« je obvezno polje",
|
||||
"Erroneous token": "Napačen žeton",
|
||||
"Afrikaans": "afrikanščina",
|
||||
"Arabic": "arabščina",
|
||||
"Armenian": "armenščina",
|
||||
"English (auto-generated)": "angleščina (samodejno ustvarjeno)",
|
||||
"Bulgarian": "bolgarščina",
|
||||
"Catalan": "katalonščina",
|
||||
"Cantonese (Hong Kong)": "kantonščina (Hongkong)",
|
||||
"Chinese (Traditional)": "kitajščina (tradicionalna)",
|
||||
"Basque": "baskovščina",
|
||||
"Czech": "češčina",
|
||||
"Bosnian": "bosanščina",
|
||||
"Chinese": "kitajščina",
|
||||
"Chinese (China)": "kitajščina (Kitajska)",
|
||||
"Dutch (auto-generated)": "nizozemščina (samodejno ustvarjeno)",
|
||||
"Esperanto": "esperanto",
|
||||
"Galician": "galicijščina",
|
||||
"German (auto-generated)": "nemščina (samodejno ustvarjeno)",
|
||||
"Hebrew": "hebrejščina",
|
||||
"Malayalam": "malajalamščina",
|
||||
"Hindi": "hindijščina",
|
||||
"Indonesian": "indonezijščina",
|
||||
"Kazakh": "kazahstanščina",
|
||||
"Indonesian (auto-generated)": "indonezijščina (samodejno generirano)",
|
||||
"Irish": "irščina",
|
||||
"Persian": "perzijščina",
|
||||
"Slovak": "slovaščina",
|
||||
"Italian": "italijanščina",
|
||||
"Maori": "maorščina",
|
||||
"Portuguese": "portugalščina",
|
||||
"Javanese": "javanščina",
|
||||
"Kyrgyz": "kirgiščina",
|
||||
"Lao": "laoščina",
|
||||
"Latin": "latinščina",
|
||||
"Mongolian": "mongolščina",
|
||||
"Portuguese (auto-generated)": "portugalščina (samodejno ustvarjeno)",
|
||||
"Sindhi": "sindščina",
|
||||
"Maltese": "malteščina",
|
||||
"Marathi": "maratščina",
|
||||
"Pashto": "paštu",
|
||||
"Polish": "poljščina",
|
||||
"Portuguese (Brazil)": "portugalščina (Brazilija)",
|
||||
"Fallback comments: ": "Nadomestni komentarji: ",
|
||||
"Gaming": "Igralništvo",
|
||||
"Russian (auto-generated)": "ruščina (samodejno ustvarjeno)",
|
||||
"Serbian": "srbščina",
|
||||
"Sinhala": "singalščina",
|
||||
"Slovenian": "slovenščina",
|
||||
"Somali": "somalijščina",
|
||||
"Spanish": "španščina",
|
||||
"Southern Sotho": "južni sotho",
|
||||
"Spanish (auto-generated)": "španščina (samodejno ustvarjeno)",
|
||||
"Spanish (Mexico)": "španščina (Mehika)",
|
||||
"Spanish (Latin America)": "španščina (Latinska Amerika)",
|
||||
"Spanish (Spain)": "španščina (Španija)",
|
||||
"Tajik": "tadžiščina",
|
||||
"Tamil": "tamilščina",
|
||||
"generic_count_weeks_0": "{{count}} tednom",
|
||||
"generic_count_weeks_1": "{{count}} tedni",
|
||||
"generic_count_weeks_2": "{{count}} tedni",
|
||||
"generic_count_weeks_3": "{{count}} tedni",
|
||||
"Swahili": "svahilščina",
|
||||
"Swedish": "švedščina",
|
||||
"Vietnamese (auto-generated)": "vietnamščina (samodejno ustvarjeno)",
|
||||
"generic_count_months_0": "{{count}} mesecem",
|
||||
"generic_count_months_1": "{{count}} meseci",
|
||||
"generic_count_months_2": "{{count}} meseci",
|
||||
"generic_count_months_3": "{{count}} meseci",
|
||||
"Uzbek": "uzbeščina",
|
||||
"Zulu": "zulujščina",
|
||||
"generic_count_seconds_0": "{{count}} sekundo",
|
||||
"generic_count_seconds_1": "{{count}} sekundami",
|
||||
"generic_count_seconds_2": "{{count}} sekundami",
|
||||
"generic_count_seconds_3": "{{count}} sekundami",
|
||||
"Popular": "Priljubljeni",
|
||||
"Music": "Glasba",
|
||||
"Movies": "Filmi",
|
||||
"YouTube comment permalink": "Stalna povezava za komentar na YouTubu",
|
||||
"search_filters_title": "Filtri",
|
||||
"preferences_locale_label": "Jezik: ",
|
||||
"Rating: ": "Ocena: ",
|
||||
"Default": "Privzeto",
|
||||
"News": "Novice",
|
||||
"Download as: ": "Prenesi kot: ",
|
||||
"(edited)": "(urejeno)",
|
||||
"View as playlist": "Poglej kot seznam predvajanja",
|
||||
"Download": "Prenesi",
|
||||
"permalink": "stalna povezava",
|
||||
"`x` marked it with a ❤": "`x` ga je označil/a z ❤",
|
||||
"channel_tab_community_label": "Skupnost",
|
||||
"search_filters_features_option_three_sixty": "360°",
|
||||
"Video mode": "Video način",
|
||||
"search_filters_features_option_c_commons": "Creative Commons",
|
||||
"search_filters_features_option_three_d": "3D",
|
||||
"Playlists": "Seznami predvajanja",
|
||||
"search_filters_date_option_none": "Katerikoli datum",
|
||||
"search_filters_date_option_month": "Ta mesec",
|
||||
"search_filters_date_option_year": "Letos",
|
||||
"search_filters_type_option_movie": "Film",
|
||||
"search_filters_duration_option_long": "Dolg (> 20 minut)",
|
||||
"search_filters_features_label": "Lastnosti",
|
||||
"search_filters_features_option_four_k": "4K",
|
||||
"search_filters_features_option_hdr": "HDR",
|
||||
"next_steps_error_message_refresh": "Osveži",
|
||||
"search_filters_date_option_hour": "Zadnja ura",
|
||||
"search_filters_features_option_purchased": "Kupljeno",
|
||||
"search_filters_sort_label": "Razvrsti po",
|
||||
"search_filters_sort_option_views": "številu ogledov",
|
||||
"Current version: ": "Trenutna različica: ",
|
||||
"search_filters_features_option_live": "V živo",
|
||||
"search_filters_features_option_hd": "HD",
|
||||
"search_filters_type_option_channel": "Kanal",
|
||||
"search_filters_type_option_show": "Pokaži",
|
||||
"search_filters_duration_label": "Trajanje",
|
||||
"search_filters_duration_option_none": "Poljubno trajanje",
|
||||
"search_filters_duration_option_short": "Kratek (< 4 minute)",
|
||||
"search_filters_duration_option_medium": "Srednji (4 - 20 minut)",
|
||||
"search_filters_features_option_vr180": "VR180",
|
||||
"search_filters_sort_option_date": "datumu nalaganja",
|
||||
"search_filters_type_option_video": "Videoposnetek",
|
||||
"search_filters_sort_option_relevance": "ustreznosti",
|
||||
"search_filters_sort_option_rating": "oceni",
|
||||
"search_filters_apply_button": "Uporabi izbrane filtre",
|
||||
"next_steps_error_message": "Po tem moraš poskusiti: ",
|
||||
"next_steps_error_message_go_to_youtube": "Pojdi na YouTube",
|
||||
"footer_source_code": "Izvorna koda",
|
||||
"footer_modfied_source_code": "Spremenjena izvorna koda",
|
||||
"user_created_playlists": "`x` ustvarjenih seznamov predvajanja",
|
||||
"adminprefs_modified_source_code_url_label": "URL do shrambe spremenjene izvorne kode",
|
||||
"videoinfo_youTube_embed_link": "Vdelaj",
|
||||
"videoinfo_invidious_embed_link": "Povezava za vdelavo",
|
||||
"crash_page_switch_instance": "poskušal/a <a href=\"`x`\">uporabiti drugo instanco</a>",
|
||||
"download_subtitles": "Podnapisi - `x` (.vtt)",
|
||||
"crash_page_refresh": "poskušal/a <a href=\"`x`\">osvežiti stran</a>",
|
||||
"crash_page_before_reporting": "Preden prijaviš napako, se prepričaj, da si:",
|
||||
"crash_page_search_issue": "preiskal/a <a href=\"`x`\">obstoječe težave na GitHubu</a>",
|
||||
"crash_page_report_issue": "Če nič od navedenega ni pomagalo, prosim <a href=\"`x`\">odpri novo težavo v GitHubu</a> (po možnosti v angleščini) in v svoje sporočilo vključi naslednje besedilo (tega besedila NE prevajaj):",
|
||||
"Popular enabled: ": "Priljubljeni omogočeni: ",
|
||||
"error_video_not_in_playlist": "Zahtevani videoposnetek ne obstaja na tem seznamu predvajanja. <a href=\"`x`\">Klikni tukaj za domačo stran seznama predvajanja.</a>",
|
||||
"channel_tab_playlists_label": "Seznami predvajanja",
|
||||
"channel_tab_shorts_label": "Kratki videoposnetki",
|
||||
"channel_tab_channels_label": "Kanali",
|
||||
"channel_tab_streams_label": "Prenosi v živo",
|
||||
"Artist: ": "Umetnik/ca: ",
|
||||
"Music in this video": "Glasba v tem videoposnetku",
|
||||
"Album: ": "Album: ",
|
||||
"Song: ": "Pesem: ",
|
||||
"Standard YouTube license": "Standardna licenca YouTube",
|
||||
"Channel Sponsor": "Sponzor kanala",
|
||||
"Download is disabled": "Prenos je onemogočen"
|
||||
}
|
@ -1 +0,0 @@
|
||||
Subproject commit 11ec372f72747c09d48ffef04843f72be67d5b54
|
@ -1,60 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Parameters
|
||||
#
|
||||
|
||||
interactive=true
|
||||
|
||||
if [ "$1" = "--no-interactive" ]; then
|
||||
interactive=false
|
||||
fi
|
||||
|
||||
#
|
||||
# Enable and start Postgres
|
||||
#
|
||||
|
||||
sudo systemctl start postgresql.service
|
||||
sudo systemctl enable postgresql.service
|
||||
|
||||
#
|
||||
# Create databse and user
|
||||
#
|
||||
|
||||
if [ "$interactive" = "true" ]; then
|
||||
sudo -u postgres -- createuser -P kemal
|
||||
sudo -u postgres -- createdb -O kemal invidious
|
||||
else
|
||||
# Generate a DB password
|
||||
if [ -z "$POSTGRES_PASS" ]; then
|
||||
echo "Generating database password"
|
||||
POSTGRES_PASS=$(tr -dc 'A-Za-z0-9.;!?{[()]}\\/' < /dev/urandom | head -c16)
|
||||
fi
|
||||
|
||||
# hostname:port:database:username:password
|
||||
echo "Writing .pgpass"
|
||||
echo "127.0.0.1:*:invidious:kemal:${POSTGRES_PASS}" > "$HOME/.pgpass"
|
||||
|
||||
sudo -u postgres -- psql -c "CREATE USER kemal WITH PASSWORD '$POSTGRES_PASS';"
|
||||
sudo -u postgres -- psql -c "CREATE DATABASE invidious WITH OWNER kemal;"
|
||||
sudo -u postgres -- psql -c "GRANT ALL ON DATABASE invidious TO kemal;"
|
||||
fi
|
||||
|
||||
|
||||
#
|
||||
# Instructions for modification of pg_hba.conf
|
||||
#
|
||||
|
||||
if [ "$interactive" = "true" ]; then
|
||||
echo
|
||||
echo "-------------"
|
||||
echo " NOTICE "
|
||||
echo "-------------"
|
||||
echo
|
||||
echo "Make sure that your postgreSQL's pg_hba.conf file contains the follwong"
|
||||
echo "lines before previous 'host' configurations:"
|
||||
echo
|
||||
echo "host invidious kemal 127.0.0.1/32 md5"
|
||||
echo "host invidious kemal ::1/128 md5"
|
||||
echo
|
||||
fi
|
@ -1,174 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Script that installs the various dependencies of invidious
|
||||
#
|
||||
# Dependencies:
|
||||
# - crystal => Language in which Invidious is developed
|
||||
# - postgres => Database server
|
||||
# - git => required to clone Invidious
|
||||
# - librsvg2-bin => For login captcha (provides 'rsvg-convert')
|
||||
#
|
||||
# - libssl-dev => Used by Crystal's SSL module (standard library)
|
||||
# - libxml2-dev => Used by Crystal's XML module (standard library)
|
||||
# - libyaml-dev => Used by Crystal's YAML module (standard library)
|
||||
# - libgmp-dev => Used by Crystal's BigNumbers module (standard library)
|
||||
# - libevent-dev => Used by crystal's internal scheduler (?)
|
||||
# - libpcre3-dev => Used by Crystal's regex engine (?)
|
||||
#
|
||||
# - libsqlite3-dev => Used to open .db files from NewPipe exports
|
||||
# - zlib1g-dev => TBD
|
||||
# - libreadline-dev => TBD
|
||||
#
|
||||
#
|
||||
# Tested on:
|
||||
# - OpenSUSE Leap 15.3
|
||||
|
||||
#
|
||||
# Load system details
|
||||
#
|
||||
|
||||
if [ -e /etc/os-release ]; then
|
||||
. /etc/os-release
|
||||
elif [ -e /usr/lib/os-release ]; then
|
||||
. /usr/lib/os-release
|
||||
else
|
||||
echo "Unsupported Linux system"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
#
|
||||
# Some variables
|
||||
#
|
||||
|
||||
repo_base_url="https://download.opensuse.org/repositories/devel:/languages:/crystal/"
|
||||
repo_end_url="devel:languages:crystal.repo"
|
||||
|
||||
apt_gpg_key="/usr/share/keyrings/crystal.gpg"
|
||||
apt_list_file="/etc/apt/sources.list.d/crystal.list"
|
||||
|
||||
yum_repo_file="/etc/yum.repos.d/crystal.repo"
|
||||
|
||||
#
|
||||
# Major install functions
|
||||
#
|
||||
|
||||
make_repo_url() {
|
||||
echo "${repo_base_url}/${1}/${repo_end_url}"
|
||||
}
|
||||
|
||||
|
||||
install_apt() {
|
||||
repo="$1"
|
||||
|
||||
echo "Adding Crystal repository"
|
||||
|
||||
curl -fsSL "${repo_base_url}/${repo}/Release.key" \
|
||||
| gpg --dearmor \
|
||||
| sudo tee "${apt_gpg_key}" > /dev/null
|
||||
|
||||
echo "deb [signed-by=${apt_gpg_key}] ${repo_base_url}/${repo}/ /" \
|
||||
| sudo tee "$apt_list_file"
|
||||
|
||||
sudo apt-get update
|
||||
|
||||
sudo apt-get install --yes --no-install-recommends \
|
||||
libssl-dev libxml2-dev libyaml-dev libgmp-dev libevent-dev \
|
||||
libpcre3-dev libreadline-dev libsqlite3-dev zlib1g-dev \
|
||||
crystal postgresql-13 git librsvg2-bin make
|
||||
}
|
||||
|
||||
install_yum() {
|
||||
repo=$(make_repo_url "$1")
|
||||
|
||||
echo "Adding Crystal repository"
|
||||
|
||||
cat << END | sudo tee "${yum_repo_file}" > /dev/null
|
||||
[crystal]
|
||||
name=Crystal
|
||||
type=rpm-md
|
||||
baseurl=${repo}/
|
||||
gpgcheck=1
|
||||
gpgkey=${repo}/repodata/repomd.xml.key
|
||||
enabled=1
|
||||
END
|
||||
|
||||
sudo yum -y install \
|
||||
openssl-devel libxml2-devel libyaml-devel gmp-devel \
|
||||
readline-devel sqlite-devel \
|
||||
crystal postgresql postgresql-server git librsvg2-tools make
|
||||
}
|
||||
|
||||
install_pacman() {
|
||||
# TODO: find an alternative to --no-confirm?
|
||||
sudo pacman -S --no-confirm \
|
||||
base-devel librsvg postgresql crystal
|
||||
}
|
||||
|
||||
install_zypper()
|
||||
{
|
||||
repo=$(make_repo_url "$1")
|
||||
|
||||
echo "Adding Crystal repository"
|
||||
sudo zypper --non-interactive addrepo -f "$repo"
|
||||
|
||||
sudo zypper --non-interactive --gpg-auto-import-keys install --no-recommends \
|
||||
libopenssl-devel libxml2-devel libyaml-devel gmp-devel libevent-devel \
|
||||
pcre-devel readline-devel sqlite3-devel zlib-devel \
|
||||
crystal postgresql postgresql-server git rsvg-convert make
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# System-specific logic
|
||||
#
|
||||
|
||||
case "$ID" in
|
||||
archlinux) install_pacman;;
|
||||
|
||||
centos) install_dnf "CentOS_${VERSION_ID}";;
|
||||
|
||||
debian)
|
||||
case "$VERSION_CODENAME" in
|
||||
sid) install_apt "Debian_Unstable";;
|
||||
bookworm) install_apt "Debian_Testing";;
|
||||
*) install_apt "Debian_${VERSION_ID}";;
|
||||
esac
|
||||
;;
|
||||
|
||||
fedora)
|
||||
if [ "$VERSION" == *"Prerelease"* ]; then
|
||||
install_dnf "Fedora_Rawhide"
|
||||
else
|
||||
install_dnf "Fedora_${VERSION}"
|
||||
fi
|
||||
;;
|
||||
|
||||
opensuse-leap) install_zypper "openSUSE_Leap_${VERSION}";;
|
||||
|
||||
opensuse-tumbleweed) install_zypper "openSUSE_Tumbleweed";;
|
||||
|
||||
rhel) install_dnf "RHEL_${VERSION_ID}";;
|
||||
|
||||
ubuntu)
|
||||
# Small workaround for recently released 22.04
|
||||
case "$VERSION_ID" in
|
||||
22.04) install_apt "xUbuntu_21.04";;
|
||||
*) install_apt "xUbuntu_${VERSION_ID}";;
|
||||
esac
|
||||
;;
|
||||
|
||||
*)
|
||||
# Try to match on ID_LIKE instead
|
||||
# Not guaranteed to 100% work
|
||||
case "$ID_LIKE" in
|
||||
archlinux) install_pacman;;
|
||||
centos) install_dnf "CentOS_${VERSION_ID}";;
|
||||
debian) install_apt "Debian_${VERSION_ID}";;
|
||||
*)
|
||||
echo "Error: distribution ${CODENAME} is not supported"
|
||||
echo "Please install dependencies manually"
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
@ -1,109 +0,0 @@
|
||||
require "../parsers_helper.cr"
|
||||
|
||||
Spectator.describe Invidious::Hashtag do
|
||||
it "parses richItemRenderer containers (test 1)" do
|
||||
# Enable mock
|
||||
test_content = load_mock("hashtag/martingarrix_page1")
|
||||
videos, _ = extract_items(test_content)
|
||||
|
||||
expect(typeof(videos)).to eq(Array(SearchItem))
|
||||
expect(videos.size).to eq(60)
|
||||
|
||||
#
|
||||
# Random video check 1
|
||||
#
|
||||
expect(typeof(videos[11])).to eq(SearchItem)
|
||||
|
||||
video_11 = videos[11].as(SearchVideo)
|
||||
|
||||
expect(video_11.id).to eq("06eSsOWcKYA")
|
||||
expect(video_11.title).to eq("Martin Garrix - Live @ Tomorrowland 2018")
|
||||
|
||||
expect(video_11.ucid).to eq("UC5H_KXkPbEsGs0tFt8R35mA")
|
||||
expect(video_11.author).to eq("Martin Garrix")
|
||||
expect(video_11.author_verified).to be_true
|
||||
|
||||
expect(video_11.published).to be_close(Time.utc - 3.years, 1.second)
|
||||
expect(video_11.length_seconds).to eq((56.minutes + 41.seconds).total_seconds.to_i32)
|
||||
expect(video_11.views).to eq(40_504_893)
|
||||
|
||||
expect(video_11.live_now).to be_false
|
||||
expect(video_11.premium).to be_false
|
||||
expect(video_11.premiere_timestamp).to be_nil
|
||||
|
||||
#
|
||||
# Random video check 2
|
||||
#
|
||||
expect(typeof(videos[35])).to eq(SearchItem)
|
||||
|
||||
video_35 = videos[35].as(SearchVideo)
|
||||
|
||||
expect(video_35.id).to eq("b9HpOAYjY9I")
|
||||
expect(video_35.title).to eq("Martin Garrix feat. Mike Yung - Dreamer (Official Video)")
|
||||
|
||||
expect(video_35.ucid).to eq("UC5H_KXkPbEsGs0tFt8R35mA")
|
||||
expect(video_35.author).to eq("Martin Garrix")
|
||||
expect(video_35.author_verified).to be_true
|
||||
|
||||
expect(video_35.published).to be_close(Time.utc - 3.years, 1.second)
|
||||
expect(video_35.length_seconds).to eq((3.minutes + 14.seconds).total_seconds.to_i32)
|
||||
expect(video_35.views).to eq(30_790_049)
|
||||
|
||||
expect(video_35.live_now).to be_false
|
||||
expect(video_35.premium).to be_false
|
||||
expect(video_35.premiere_timestamp).to be_nil
|
||||
end
|
||||
|
||||
it "parses richItemRenderer containers (test 2)" do
|
||||
# Enable mock
|
||||
test_content = load_mock("hashtag/martingarrix_page2")
|
||||
videos, _ = extract_items(test_content)
|
||||
|
||||
expect(typeof(videos)).to eq(Array(SearchItem))
|
||||
expect(videos.size).to eq(60)
|
||||
|
||||
#
|
||||
# Random video check 1
|
||||
#
|
||||
expect(typeof(videos[41])).to eq(SearchItem)
|
||||
|
||||
video_41 = videos[41].as(SearchVideo)
|
||||
|
||||
expect(video_41.id).to eq("qhstH17zAjs")
|
||||
expect(video_41.title).to eq("Martin Garrix Radio - Episode 391")
|
||||
|
||||
expect(video_41.ucid).to eq("UC5H_KXkPbEsGs0tFt8R35mA")
|
||||
expect(video_41.author).to eq("Martin Garrix")
|
||||
expect(video_41.author_verified).to be_true
|
||||
|
||||
expect(video_41.published).to be_close(Time.utc - 2.months, 1.second)
|
||||
expect(video_41.length_seconds).to eq((1.hour).total_seconds.to_i32)
|
||||
expect(video_41.views).to eq(63_240)
|
||||
|
||||
expect(video_41.live_now).to be_false
|
||||
expect(video_41.premium).to be_false
|
||||
expect(video_41.premiere_timestamp).to be_nil
|
||||
|
||||
#
|
||||
# Random video check 2
|
||||
#
|
||||
expect(typeof(videos[48])).to eq(SearchItem)
|
||||
|
||||
video_48 = videos[48].as(SearchVideo)
|
||||
|
||||
expect(video_48.id).to eq("lqGvW0NIfdc")
|
||||
expect(video_48.title).to eq("Martin Garrix SENTIO Full Album Mix by Sakul")
|
||||
|
||||
expect(video_48.ucid).to eq("UC3833PXeLTS6yRpwGMQpp4Q")
|
||||
expect(video_48.author).to eq("SAKUL")
|
||||
expect(video_48.author_verified).to be_false
|
||||
|
||||
expect(video_48.published).to be_close(Time.utc - 3.weeks, 1.second)
|
||||
expect(video_48.length_seconds).to eq((35.minutes + 46.seconds).total_seconds.to_i32)
|
||||
expect(video_48.views).to eq(68_704)
|
||||
|
||||
expect(video_48.live_now).to be_false
|
||||
expect(video_48.premium).to be_false
|
||||
expect(video_48.premiere_timestamp).to be_nil
|
||||
end
|
||||
end
|
@ -1,371 +0,0 @@
|
||||
require "../../../src/invidious/search/filters"
|
||||
|
||||
require "http/params"
|
||||
require "spectator"
|
||||
|
||||
Spectator.configure do |config|
|
||||
config.fail_blank
|
||||
config.randomize
|
||||
end
|
||||
|
||||
FEATURES_TEXT = {
|
||||
Invidious::Search::Filters::Features::Live => "live",
|
||||
Invidious::Search::Filters::Features::FourK => "4k",
|
||||
Invidious::Search::Filters::Features::HD => "hd",
|
||||
Invidious::Search::Filters::Features::Subtitles => "subtitles",
|
||||
Invidious::Search::Filters::Features::CCommons => "commons",
|
||||
Invidious::Search::Filters::Features::ThreeSixty => "360",
|
||||
Invidious::Search::Filters::Features::VR180 => "vr180",
|
||||
Invidious::Search::Filters::Features::ThreeD => "3d",
|
||||
Invidious::Search::Filters::Features::HDR => "hdr",
|
||||
Invidious::Search::Filters::Features::Location => "location",
|
||||
Invidious::Search::Filters::Features::Purchased => "purchased",
|
||||
}
|
||||
|
||||
Spectator.describe Invidious::Search::Filters do
|
||||
# -------------------
|
||||
# Decode (legacy)
|
||||
# -------------------
|
||||
|
||||
describe "#from_legacy_filters" do
|
||||
it "Decodes channel: filter" do
|
||||
query = "test channel:UC123456 request"
|
||||
|
||||
fltr, chan, qury, subs = described_class.from_legacy_filters(query)
|
||||
|
||||
expect(fltr).to eq(described_class.new)
|
||||
expect(chan).to eq("UC123456")
|
||||
expect(qury).to eq("test request")
|
||||
expect(subs).to be_false
|
||||
end
|
||||
|
||||
it "Decodes user: filter" do
|
||||
query = "user:LinusTechTips broke something (again)"
|
||||
|
||||
fltr, chan, qury, subs = described_class.from_legacy_filters(query)
|
||||
|
||||
expect(fltr).to eq(described_class.new)
|
||||
expect(chan).to eq("LinusTechTips")
|
||||
expect(qury).to eq("broke something (again)")
|
||||
expect(subs).to be_false
|
||||
end
|
||||
|
||||
it "Decodes type: filter" do
|
||||
Invidious::Search::Filters::Type.each do |value|
|
||||
query = "Eiffel 65 - Blue [1 Hour] type:#{value}"
|
||||
|
||||
fltr, chan, qury, subs = described_class.from_legacy_filters(query)
|
||||
|
||||
expect(fltr).to eq(described_class.new(type: value))
|
||||
expect(chan).to eq("")
|
||||
expect(qury).to eq("Eiffel 65 - Blue [1 Hour]")
|
||||
expect(subs).to be_false
|
||||
end
|
||||
end
|
||||
|
||||
it "Decodes content_type: filter" do
|
||||
Invidious::Search::Filters::Type.each do |value|
|
||||
query = "I like to watch content_type:#{value}"
|
||||
|
||||
fltr, chan, qury, subs = described_class.from_legacy_filters(query)
|
||||
|
||||
expect(fltr).to eq(described_class.new(type: value))
|
||||
expect(chan).to eq("")
|
||||
expect(qury).to eq("I like to watch")
|
||||
expect(subs).to be_false
|
||||
end
|
||||
end
|
||||
|
||||
it "Decodes date: filter" do
|
||||
Invidious::Search::Filters::Date.each do |value|
|
||||
query = "This date:#{value} is old!"
|
||||
|
||||
fltr, chan, qury, subs = described_class.from_legacy_filters(query)
|
||||
|
||||
expect(fltr).to eq(described_class.new(date: value))
|
||||
expect(chan).to eq("")
|
||||
expect(qury).to eq("This is old!")
|
||||
expect(subs).to be_false
|
||||
end
|
||||
end
|
||||
|
||||
it "Decodes duration: filter" do
|
||||
Invidious::Search::Filters::Duration.each do |value|
|
||||
query = "This duration:#{value} is old!"
|
||||
|
||||
fltr, chan, qury, subs = described_class.from_legacy_filters(query)
|
||||
|
||||
expect(fltr).to eq(described_class.new(duration: value))
|
||||
expect(chan).to eq("")
|
||||
expect(qury).to eq("This is old!")
|
||||
expect(subs).to be_false
|
||||
end
|
||||
end
|
||||
|
||||
it "Decodes feature: filter" do
|
||||
Invidious::Search::Filters::Features.each do |value|
|
||||
string = FEATURES_TEXT[value]
|
||||
query = "I like my precious feature:#{string} ^^"
|
||||
|
||||
fltr, chan, qury, subs = described_class.from_legacy_filters(query)
|
||||
|
||||
expect(fltr).to eq(described_class.new(features: value))
|
||||
expect(chan).to eq("")
|
||||
expect(qury).to eq("I like my precious ^^")
|
||||
expect(subs).to be_false
|
||||
end
|
||||
end
|
||||
|
||||
it "Decodes features: filter" do
|
||||
query = "This search has many features:vr180,cc,hdr :o"
|
||||
|
||||
fltr, chan, qury, subs = described_class.from_legacy_filters(query)
|
||||
|
||||
features = Invidious::Search::Filters::Features.flags(HDR, VR180, CCommons)
|
||||
|
||||
expect(fltr).to eq(described_class.new(features: features))
|
||||
expect(chan).to eq("")
|
||||
expect(qury).to eq("This search has many :o")
|
||||
expect(subs).to be_false
|
||||
end
|
||||
|
||||
it "Decodes sort: filter" do
|
||||
Invidious::Search::Filters::Sort.each do |value|
|
||||
query = "Computer? sort:#{value} my files!"
|
||||
|
||||
fltr, chan, qury, subs = described_class.from_legacy_filters(query)
|
||||
|
||||
expect(fltr).to eq(described_class.new(sort: value))
|
||||
expect(chan).to eq("")
|
||||
expect(qury).to eq("Computer? my files!")
|
||||
expect(subs).to be_false
|
||||
end
|
||||
end
|
||||
|
||||
it "Decodes subscriptions: filter" do
|
||||
query = "enable subscriptions:true"
|
||||
|
||||
fltr, chan, qury, subs = described_class.from_legacy_filters(query)
|
||||
|
||||
expect(fltr).to eq(described_class.new)
|
||||
expect(chan).to eq("")
|
||||
expect(qury).to eq("enable")
|
||||
expect(subs).to be_true
|
||||
end
|
||||
|
||||
it "Ignores junk data" do
|
||||
query = "duration:I sort:like type:cleaning features:stuff date:up!"
|
||||
|
||||
fltr, chan, qury, subs = described_class.from_legacy_filters(query)
|
||||
|
||||
expect(fltr).to eq(described_class.new)
|
||||
expect(chan).to eq("")
|
||||
expect(qury).to eq("")
|
||||
expect(subs).to be_false
|
||||
end
|
||||
|
||||
it "Keeps unknown keys" do
|
||||
query = "to:be or:not to:be"
|
||||
|
||||
fltr, chan, qury, subs = described_class.from_legacy_filters(query)
|
||||
|
||||
expect(fltr).to eq(described_class.new)
|
||||
expect(chan).to eq("")
|
||||
expect(qury).to eq("to:be or:not to:be")
|
||||
expect(subs).to be_false
|
||||
end
|
||||
end
|
||||
|
||||
# -------------------
|
||||
# Decode (URL)
|
||||
# -------------------
|
||||
|
||||
describe "#from_iv_params" do
|
||||
it "Decodes type= filter" do
|
||||
Invidious::Search::Filters::Type.each do |value|
|
||||
params = HTTP::Params.parse("type=#{value}")
|
||||
|
||||
expect(described_class.from_iv_params(params))
|
||||
.to eq(described_class.new(type: value))
|
||||
end
|
||||
end
|
||||
|
||||
it "Decodes date= filter" do
|
||||
Invidious::Search::Filters::Date.each do |value|
|
||||
params = HTTP::Params.parse("date=#{value}")
|
||||
|
||||
expect(described_class.from_iv_params(params))
|
||||
.to eq(described_class.new(date: value))
|
||||
end
|
||||
end
|
||||
|
||||
it "Decodes duration= filter" do
|
||||
Invidious::Search::Filters::Duration.each do |value|
|
||||
params = HTTP::Params.parse("duration=#{value}")
|
||||
|
||||
expect(described_class.from_iv_params(params))
|
||||
.to eq(described_class.new(duration: value))
|
||||
end
|
||||
end
|
||||
|
||||
it "Decodes features= filter (single)" do
|
||||
Invidious::Search::Filters::Features.each do |value|
|
||||
string = described_class.format_features(value)
|
||||
params = HTTP::Params.parse("features=#{string}")
|
||||
|
||||
expect(described_class.from_iv_params(params))
|
||||
.to eq(described_class.new(features: value))
|
||||
end
|
||||
end
|
||||
|
||||
it "Decodes features= filter (multiple - comma separated)" do
|
||||
features = Invidious::Search::Filters::Features.flags(HDR, VR180, CCommons)
|
||||
params = HTTP::Params.parse("features=vr180%2Ccc%2Chdr") # %2C is a comma
|
||||
|
||||
expect(described_class.from_iv_params(params))
|
||||
.to eq(described_class.new(features: features))
|
||||
end
|
||||
|
||||
it "Decodes features= filter (multiple - URL parameters)" do
|
||||
features = Invidious::Search::Filters::Features.flags(ThreeSixty, HD, FourK)
|
||||
params = HTTP::Params.parse("features=4k&features=360&features=hd")
|
||||
|
||||
expect(described_class.from_iv_params(params))
|
||||
.to eq(described_class.new(features: features))
|
||||
end
|
||||
|
||||
it "Decodes sort= filter" do
|
||||
Invidious::Search::Filters::Sort.each do |value|
|
||||
params = HTTP::Params.parse("sort=#{value}")
|
||||
|
||||
expect(described_class.from_iv_params(params))
|
||||
.to eq(described_class.new(sort: value))
|
||||
end
|
||||
end
|
||||
|
||||
it "Ignores junk data" do
|
||||
params = HTTP::Params.parse("foo=bar&sort=views&answer=42&type=channel")
|
||||
|
||||
expect(described_class.from_iv_params(params)).to eq(
|
||||
described_class.new(
|
||||
sort: Invidious::Search::Filters::Sort::Views,
|
||||
type: Invidious::Search::Filters::Type::Channel
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
# -------------------
|
||||
# Encode (URL)
|
||||
# -------------------
|
||||
|
||||
describe "#to_iv_params" do
|
||||
it "Encodes date filter" do
|
||||
Invidious::Search::Filters::Date.each do |value|
|
||||
filters = described_class.new(date: value)
|
||||
params = filters.to_iv_params
|
||||
|
||||
if value.none?
|
||||
expect("#{params}").to eq("")
|
||||
else
|
||||
expect("#{params}").to eq("date=#{value.to_s.underscore}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "Encodes type filter" do
|
||||
Invidious::Search::Filters::Type.each do |value|
|
||||
filters = described_class.new(type: value)
|
||||
params = filters.to_iv_params
|
||||
|
||||
if value.all?
|
||||
expect("#{params}").to eq("")
|
||||
else
|
||||
expect("#{params}").to eq("type=#{value.to_s.underscore}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "Encodes duration filter" do
|
||||
Invidious::Search::Filters::Duration.each do |value|
|
||||
filters = described_class.new(duration: value)
|
||||
params = filters.to_iv_params
|
||||
|
||||
if value.none?
|
||||
expect("#{params}").to eq("")
|
||||
else
|
||||
expect("#{params}").to eq("duration=#{value.to_s.underscore}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "Encodes features filter (single)" do
|
||||
Invidious::Search::Filters::Features.each do |value|
|
||||
string = described_class.format_features(value)
|
||||
filters = described_class.new(features: value)
|
||||
|
||||
expect("#{filters.to_iv_params}")
|
||||
.to eq("features=" + FEATURES_TEXT[value])
|
||||
end
|
||||
end
|
||||
|
||||
it "Encodes features filter (multiple)" do
|
||||
features = Invidious::Search::Filters::Features.flags(Subtitles, Live, ThreeSixty)
|
||||
filters = described_class.new(features: features)
|
||||
|
||||
expect("#{filters.to_iv_params}")
|
||||
.to eq("features=live%2Csubtitles%2C360") # %2C is a comma
|
||||
end
|
||||
|
||||
it "Encodes sort filter" do
|
||||
Invidious::Search::Filters::Sort.each do |value|
|
||||
filters = described_class.new(sort: value)
|
||||
params = filters.to_iv_params
|
||||
|
||||
if value.relevance?
|
||||
expect("#{params}").to eq("")
|
||||
else
|
||||
expect("#{params}").to eq("sort=#{value.to_s.underscore}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "Encodes multiple filters" do
|
||||
filters = described_class.new(
|
||||
date: Invidious::Search::Filters::Date::Today,
|
||||
duration: Invidious::Search::Filters::Duration::Medium,
|
||||
features: Invidious::Search::Filters::Features.flags(Location, Purchased),
|
||||
sort: Invidious::Search::Filters::Sort::Relevance
|
||||
)
|
||||
|
||||
params = filters.to_iv_params
|
||||
|
||||
# Check the `date` param
|
||||
expect(params).to have_key("date")
|
||||
expect(params.fetch_all("date")).to contain_exactly("today")
|
||||
|
||||
# Check the `type` param
|
||||
expect(params).to_not have_key("type")
|
||||
expect(params["type"]?).to be_nil
|
||||
|
||||
# Check the `duration` param
|
||||
expect(params).to have_key("duration")
|
||||
expect(params.fetch_all("duration")).to contain_exactly("medium")
|
||||
|
||||
# Check the `features` param
|
||||
expect(params).to have_key("features")
|
||||
expect(params.fetch_all("features")).to contain_exactly("location,purchased")
|
||||
|
||||
# Check the `sort` param
|
||||
expect(params).to_not have_key("sort")
|
||||
expect(params["sort"]?).to be_nil
|
||||
|
||||
# Check if there aren't other parameters
|
||||
params.delete("date")
|
||||
params.delete("duration")
|
||||
params.delete("features")
|
||||
|
||||
expect(params).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
@ -1,242 +0,0 @@
|
||||
require "../../../src/invidious/search/filters"
|
||||
require "../../../src/invidious/search/query"
|
||||
|
||||
require "http/params"
|
||||
require "spectator"
|
||||
|
||||
Spectator.configure do |config|
|
||||
config.fail_blank
|
||||
config.randomize
|
||||
end
|
||||
|
||||
Spectator.describe Invidious::Search::Query do
|
||||
describe Type::Regular do
|
||||
# -------------------
|
||||
# Query parsing
|
||||
# -------------------
|
||||
|
||||
it "parses query with URL prameters (q)" do
|
||||
query = described_class.new(
|
||||
HTTP::Params.parse("q=What+is+Love+10+hour&type=video&duration=long"),
|
||||
Invidious::Search::Query::Type::Regular, nil
|
||||
)
|
||||
|
||||
expect(query.type).to eq(Invidious::Search::Query::Type::Regular)
|
||||
expect(query.channel).to be_empty
|
||||
expect(query.text).to eq("What is Love 10 hour")
|
||||
|
||||
expect(query.filters).to eq(
|
||||
Invidious::Search::Filters.new(
|
||||
type: Invidious::Search::Filters::Type::Video,
|
||||
duration: Invidious::Search::Filters::Duration::Long
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
it "parses query with URL prameters (search_query)" do
|
||||
query = described_class.new(
|
||||
HTTP::Params.parse("search_query=What+is+Love+10+hour&type=video&duration=long"),
|
||||
Invidious::Search::Query::Type::Regular, nil
|
||||
)
|
||||
|
||||
expect(query.type).to eq(Invidious::Search::Query::Type::Regular)
|
||||
expect(query.channel).to be_empty
|
||||
expect(query.text).to eq("What is Love 10 hour")
|
||||
|
||||
expect(query.filters).to eq(
|
||||
Invidious::Search::Filters.new(
|
||||
type: Invidious::Search::Filters::Type::Video,
|
||||
duration: Invidious::Search::Filters::Duration::Long
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
it "parses query with legacy filters (q)" do
|
||||
query = described_class.new(
|
||||
HTTP::Params.parse("q=Nyan+cat+duration:long"),
|
||||
Invidious::Search::Query::Type::Regular, nil
|
||||
)
|
||||
|
||||
expect(query.type).to eq(Invidious::Search::Query::Type::Regular)
|
||||
expect(query.channel).to be_empty
|
||||
expect(query.text).to eq("Nyan cat")
|
||||
|
||||
expect(query.filters).to eq(
|
||||
Invidious::Search::Filters.new(
|
||||
duration: Invidious::Search::Filters::Duration::Long
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
it "parses query with legacy filters (search_query)" do
|
||||
query = described_class.new(
|
||||
HTTP::Params.parse("search_query=Nyan+cat+duration:long"),
|
||||
Invidious::Search::Query::Type::Regular, nil
|
||||
)
|
||||
|
||||
expect(query.type).to eq(Invidious::Search::Query::Type::Regular)
|
||||
expect(query.channel).to be_empty
|
||||
expect(query.text).to eq("Nyan cat")
|
||||
|
||||
expect(query.filters).to eq(
|
||||
Invidious::Search::Filters.new(
|
||||
duration: Invidious::Search::Filters::Duration::Long
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
it "parses query with both URL params and legacy filters" do
|
||||
query = described_class.new(
|
||||
HTTP::Params.parse("q=Vamos+a+la+playa+duration:long&type=Video&date=year"),
|
||||
Invidious::Search::Query::Type::Regular, nil
|
||||
)
|
||||
|
||||
expect(query.type).to eq(Invidious::Search::Query::Type::Regular)
|
||||
expect(query.channel).to be_empty
|
||||
expect(query.text).to eq("Vamos a la playa duration:long")
|
||||
|
||||
expect(query.filters).to eq(
|
||||
Invidious::Search::Filters.new(
|
||||
type: Invidious::Search::Filters::Type::Video,
|
||||
date: Invidious::Search::Filters::Date::Year
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
# -------------------
|
||||
# Type switching
|
||||
# -------------------
|
||||
|
||||
it "switches to channel search (URL param)" do
|
||||
query = described_class.new(
|
||||
HTTP::Params.parse("q=thunderbolt+4&channel=UC0vBXGSyV14uvJ4hECDOl0Q"),
|
||||
Invidious::Search::Query::Type::Regular, nil
|
||||
)
|
||||
|
||||
expect(query.type).to eq(Invidious::Search::Query::Type::Channel)
|
||||
expect(query.channel).to eq("UC0vBXGSyV14uvJ4hECDOl0Q")
|
||||
expect(query.text).to eq("thunderbolt 4")
|
||||
expect(query.filters.default?).to be_true
|
||||
end
|
||||
|
||||
it "switches to channel search (legacy)" do
|
||||
query = described_class.new(
|
||||
HTTP::Params.parse("q=channel%3AUCRPdsCVuH53rcbTcEkuY4uQ+rdna3"),
|
||||
Invidious::Search::Query::Type::Regular, nil
|
||||
)
|
||||
|
||||
expect(query.type).to eq(Invidious::Search::Query::Type::Channel)
|
||||
expect(query.channel).to eq("UCRPdsCVuH53rcbTcEkuY4uQ")
|
||||
expect(query.text).to eq("rdna3")
|
||||
expect(query.filters.default?).to be_true
|
||||
end
|
||||
|
||||
it "switches to subscriptions search" do
|
||||
query = described_class.new(
|
||||
HTTP::Params.parse("q=subscriptions:true+tunak+tunak+tun"),
|
||||
Invidious::Search::Query::Type::Regular, nil
|
||||
)
|
||||
|
||||
expect(query.type).to eq(Invidious::Search::Query::Type::Subscriptions)
|
||||
expect(query.channel).to be_empty
|
||||
expect(query.text).to eq("tunak tunak tun")
|
||||
expect(query.filters.default?).to be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe Type::Channel do
|
||||
it "ignores extra parameters" do
|
||||
query = described_class.new(
|
||||
HTTP::Params.parse("q=Take+on+me+channel%3AUC12345679&type=video&date=year"),
|
||||
Invidious::Search::Query::Type::Channel, nil
|
||||
)
|
||||
|
||||
expect(query.type).to eq(Invidious::Search::Query::Type::Channel)
|
||||
expect(query.channel).to be_empty
|
||||
expect(query.text).to eq("Take on me")
|
||||
expect(query.filters.default?).to be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe Type::Subscriptions do
|
||||
it "works" do
|
||||
query = described_class.new(
|
||||
HTTP::Params.parse("q=Harlem+shake&type=video&date=year"),
|
||||
Invidious::Search::Query::Type::Subscriptions, nil
|
||||
)
|
||||
|
||||
expect(query.type).to eq(Invidious::Search::Query::Type::Subscriptions)
|
||||
expect(query.channel).to be_empty
|
||||
expect(query.text).to eq("Harlem shake")
|
||||
|
||||
expect(query.filters).to eq(
|
||||
Invidious::Search::Filters.new(
|
||||
type: Invidious::Search::Filters::Type::Video,
|
||||
date: Invidious::Search::Filters::Date::Year
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe Type::Playlist do
|
||||
it "ignores extra parameters" do
|
||||
query = described_class.new(
|
||||
HTTP::Params.parse("q=Harlem+shake+type:video+date:year&channel=UC12345679"),
|
||||
Invidious::Search::Query::Type::Playlist, nil
|
||||
)
|
||||
|
||||
expect(query.type).to eq(Invidious::Search::Query::Type::Playlist)
|
||||
expect(query.channel).to be_empty
|
||||
expect(query.text).to eq("Harlem shake")
|
||||
|
||||
expect(query.filters).to eq(
|
||||
Invidious::Search::Filters.new(
|
||||
type: Invidious::Search::Filters::Type::Video,
|
||||
date: Invidious::Search::Filters::Date::Year
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#to_http_params" do
|
||||
it "formats regular search" do
|
||||
query = described_class.new(
|
||||
HTTP::Params.parse("q=The+Simpsons+hiding+in+bush&duration=short"),
|
||||
Invidious::Search::Query::Type::Regular, nil
|
||||
)
|
||||
|
||||
params = query.to_http_params
|
||||
|
||||
expect(params).to have_key("duration")
|
||||
expect(params["duration"]?).to eq("short")
|
||||
|
||||
expect(params).to have_key("q")
|
||||
expect(params["q"]?).to eq("The Simpsons hiding in bush")
|
||||
|
||||
# Check if there aren't other parameters
|
||||
params.delete("duration")
|
||||
params.delete("q")
|
||||
expect(params).to be_empty
|
||||
end
|
||||
|
||||
it "formats channel search" do
|
||||
query = described_class.new(
|
||||
HTTP::Params.parse("q=channel:UC2DjFE7Xf11URZqWBigcVOQ%20multimeter"),
|
||||
Invidious::Search::Query::Type::Regular, nil
|
||||
)
|
||||
|
||||
params = query.to_http_params
|
||||
|
||||
expect(params).to have_key("channel")
|
||||
expect(params["channel"]?).to eq("UC2DjFE7Xf11URZqWBigcVOQ")
|
||||
|
||||
expect(params).to have_key("q")
|
||||
expect(params["q"]?).to eq("multimeter")
|
||||
|
||||
# Check if there aren't other parameters
|
||||
params.delete("channel")
|
||||
params.delete("q")
|
||||
expect(params).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
@ -1,143 +0,0 @@
|
||||
require "../../../src/invidious/search/filters"
|
||||
|
||||
require "http/params"
|
||||
require "spectator"
|
||||
|
||||
Spectator.configure do |config|
|
||||
config.fail_blank
|
||||
config.randomize
|
||||
end
|
||||
|
||||
# Encoded filter values are extracted from the search
|
||||
# page of Youtube with any browser devtools HTML inspector.
|
||||
|
||||
DATE_FILTERS = {
|
||||
Invidious::Search::Filters::Date::Hour => "EgIIAQ%3D%3D",
|
||||
Invidious::Search::Filters::Date::Today => "EgIIAg%3D%3D",
|
||||
Invidious::Search::Filters::Date::Week => "EgIIAw%3D%3D",
|
||||
Invidious::Search::Filters::Date::Month => "EgIIBA%3D%3D",
|
||||
Invidious::Search::Filters::Date::Year => "EgIIBQ%3D%3D",
|
||||
}
|
||||
|
||||
TYPE_FILTERS = {
|
||||
Invidious::Search::Filters::Type::Video => "EgIQAQ%3D%3D",
|
||||
Invidious::Search::Filters::Type::Channel => "EgIQAg%3D%3D",
|
||||
Invidious::Search::Filters::Type::Playlist => "EgIQAw%3D%3D",
|
||||
Invidious::Search::Filters::Type::Movie => "EgIQBA%3D%3D",
|
||||
}
|
||||
|
||||
DURATION_FILTERS = {
|
||||
Invidious::Search::Filters::Duration::Short => "EgIYAQ%3D%3D",
|
||||
Invidious::Search::Filters::Duration::Medium => "EgIYAw%3D%3D",
|
||||
Invidious::Search::Filters::Duration::Long => "EgIYAg%3D%3D",
|
||||
}
|
||||
|
||||
FEATURE_FILTERS = {
|
||||
Invidious::Search::Filters::Features::Live => "EgJAAQ%3D%3D",
|
||||
Invidious::Search::Filters::Features::FourK => "EgJwAQ%3D%3D",
|
||||
Invidious::Search::Filters::Features::HD => "EgIgAQ%3D%3D",
|
||||
Invidious::Search::Filters::Features::Subtitles => "EgIoAQ%3D%3D",
|
||||
Invidious::Search::Filters::Features::CCommons => "EgIwAQ%3D%3D",
|
||||
Invidious::Search::Filters::Features::ThreeSixty => "EgJ4AQ%3D%3D",
|
||||
Invidious::Search::Filters::Features::VR180 => "EgPQAQE%3D",
|
||||
Invidious::Search::Filters::Features::ThreeD => "EgI4AQ%3D%3D",
|
||||
Invidious::Search::Filters::Features::HDR => "EgPIAQE%3D",
|
||||
Invidious::Search::Filters::Features::Location => "EgO4AQE%3D",
|
||||
Invidious::Search::Filters::Features::Purchased => "EgJIAQ%3D%3D",
|
||||
}
|
||||
|
||||
SORT_FILTERS = {
|
||||
Invidious::Search::Filters::Sort::Relevance => "",
|
||||
Invidious::Search::Filters::Sort::Date => "CAI%3D",
|
||||
Invidious::Search::Filters::Sort::Views => "CAM%3D",
|
||||
Invidious::Search::Filters::Sort::Rating => "CAE%3D",
|
||||
}
|
||||
|
||||
Spectator.describe Invidious::Search::Filters do
|
||||
# -------------------
|
||||
# Encode YT params
|
||||
# -------------------
|
||||
|
||||
describe "#to_yt_params" do
|
||||
sample DATE_FILTERS do |value, result|
|
||||
it "Encodes upload date filter '#{value}'" do
|
||||
expect(described_class.new(date: value).to_yt_params).to eq(result)
|
||||
end
|
||||
end
|
||||
|
||||
sample TYPE_FILTERS do |value, result|
|
||||
it "Encodes content type filter '#{value}'" do
|
||||
expect(described_class.new(type: value).to_yt_params).to eq(result)
|
||||
end
|
||||
end
|
||||
|
||||
sample DURATION_FILTERS do |value, result|
|
||||
it "Encodes duration filter '#{value}'" do
|
||||
expect(described_class.new(duration: value).to_yt_params).to eq(result)
|
||||
end
|
||||
end
|
||||
|
||||
sample FEATURE_FILTERS do |value, result|
|
||||
it "Encodes feature filter '#{value}'" do
|
||||
expect(described_class.new(features: value).to_yt_params).to eq(result)
|
||||
end
|
||||
end
|
||||
|
||||
sample SORT_FILTERS do |value, result|
|
||||
it "Encodes sort filter '#{value}'" do
|
||||
expect(described_class.new(sort: value).to_yt_params).to eq(result)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# -------------------
|
||||
# Decode YT params
|
||||
# -------------------
|
||||
|
||||
describe "#from_yt_params" do
|
||||
sample DATE_FILTERS do |value, encoded|
|
||||
it "Decodes upload date filter '#{value}'" do
|
||||
params = HTTP::Params.parse("sp=#{encoded}")
|
||||
|
||||
expect(described_class.from_yt_params(params))
|
||||
.to eq(described_class.new(date: value))
|
||||
end
|
||||
end
|
||||
|
||||
sample TYPE_FILTERS do |value, encoded|
|
||||
it "Decodes content type filter '#{value}'" do
|
||||
params = HTTP::Params.parse("sp=#{encoded}")
|
||||
|
||||
expect(described_class.from_yt_params(params))
|
||||
.to eq(described_class.new(type: value))
|
||||
end
|
||||
end
|
||||
|
||||
sample DURATION_FILTERS do |value, encoded|
|
||||
it "Decodes duration filter '#{value}'" do
|
||||
params = HTTP::Params.parse("sp=#{encoded}")
|
||||
|
||||
expect(described_class.from_yt_params(params))
|
||||
.to eq(described_class.new(duration: value))
|
||||
end
|
||||
end
|
||||
|
||||
sample FEATURE_FILTERS do |value, encoded|
|
||||
it "Decodes feature filter '#{value}'" do
|
||||
params = HTTP::Params.parse("sp=#{encoded}")
|
||||
|
||||
expect(described_class.from_yt_params(params))
|
||||
.to eq(described_class.new(features: value))
|
||||
end
|
||||
end
|
||||
|
||||
sample SORT_FILTERS do |value, encoded|
|
||||
it "Decodes sort filter '#{value}'" do
|
||||
params = HTTP::Params.parse("sp=#{encoded}")
|
||||
|
||||
expect(described_class.from_yt_params(params))
|
||||
.to eq(described_class.new(sort: value))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,46 +0,0 @@
|
||||
require "../spec_helper"
|
||||
|
||||
Spectator.describe "Utils" do
|
||||
describe "decode_date" do
|
||||
it "parses short dates (en-US)" do
|
||||
expect(decode_date("1s ago")).to be_close(Time.utc - 1.second, 500.milliseconds)
|
||||
expect(decode_date("2min ago")).to be_close(Time.utc - 2.minutes, 500.milliseconds)
|
||||
expect(decode_date("3h ago")).to be_close(Time.utc - 3.hours, 500.milliseconds)
|
||||
expect(decode_date("4d ago")).to be_close(Time.utc - 4.days, 500.milliseconds)
|
||||
expect(decode_date("5w ago")).to be_close(Time.utc - 5.weeks, 500.milliseconds)
|
||||
expect(decode_date("6mo ago")).to be_close(Time.utc - 6.months, 500.milliseconds)
|
||||
expect(decode_date("7y ago")).to be_close(Time.utc - 7.years, 500.milliseconds)
|
||||
end
|
||||
|
||||
it "parses short dates (en-GB)" do
|
||||
expect(decode_date("55s ago")).to be_close(Time.utc - 55.seconds, 500.milliseconds)
|
||||
expect(decode_date("44min ago")).to be_close(Time.utc - 44.minutes, 500.milliseconds)
|
||||
expect(decode_date("22hr ago")).to be_close(Time.utc - 22.hours, 500.milliseconds)
|
||||
expect(decode_date("1day ago")).to be_close(Time.utc - 1.day, 500.milliseconds)
|
||||
expect(decode_date("2days ago")).to be_close(Time.utc - 2.days, 500.milliseconds)
|
||||
expect(decode_date("3wk ago")).to be_close(Time.utc - 3.weeks, 500.milliseconds)
|
||||
expect(decode_date("11mo ago")).to be_close(Time.utc - 11.months, 500.milliseconds)
|
||||
expect(decode_date("11yr ago")).to be_close(Time.utc - 11.years, 500.milliseconds)
|
||||
end
|
||||
|
||||
it "parses long forms (singular)" do
|
||||
expect(decode_date("1 second ago")).to be_close(Time.utc - 1.second, 500.milliseconds)
|
||||
expect(decode_date("1 minute ago")).to be_close(Time.utc - 1.minute, 500.milliseconds)
|
||||
expect(decode_date("1 hour ago")).to be_close(Time.utc - 1.hour, 500.milliseconds)
|
||||
expect(decode_date("1 day ago")).to be_close(Time.utc - 1.day, 500.milliseconds)
|
||||
expect(decode_date("1 week ago")).to be_close(Time.utc - 1.week, 500.milliseconds)
|
||||
expect(decode_date("1 month ago")).to be_close(Time.utc - 1.month, 500.milliseconds)
|
||||
expect(decode_date("1 year ago")).to be_close(Time.utc - 1.year, 500.milliseconds)
|
||||
end
|
||||
|
||||
it "parses long forms (plural)" do
|
||||
expect(decode_date("5 seconds ago")).to be_close(Time.utc - 5.seconds, 500.milliseconds)
|
||||
expect(decode_date("17 minutes ago")).to be_close(Time.utc - 17.minutes, 500.milliseconds)
|
||||
expect(decode_date("23 hours ago")).to be_close(Time.utc - 23.hours, 500.milliseconds)
|
||||
expect(decode_date("3 days ago")).to be_close(Time.utc - 3.days, 500.milliseconds)
|
||||
expect(decode_date("2 weeks ago")).to be_close(Time.utc - 2.weeks, 500.milliseconds)
|
||||
expect(decode_date("9 months ago")).to be_close(Time.utc - 9.months, 500.milliseconds)
|
||||
expect(decode_date("8 years ago")).to be_close(Time.utc - 8.years, 500.milliseconds)
|
||||
end
|
||||
end
|
||||
end
|
@ -1,111 +0,0 @@
|
||||
require "../../parsers_helper.cr"
|
||||
|
||||
Spectator.describe "parse_video_info" do
|
||||
it "parses scheduled livestreams data" do
|
||||
# Enable mock
|
||||
_player = load_mock("video/scheduled_live_PBD-Podcast.player")
|
||||
_next = load_mock("video/scheduled_live_PBD-Podcast.next")
|
||||
|
||||
raw_data = _player.merge!(_next)
|
||||
info = parse_video_info("N-yVic7BbY0", raw_data)
|
||||
|
||||
# Some basic verifications
|
||||
expect(typeof(info)).to eq(Hash(String, JSON::Any))
|
||||
|
||||
expect(info["videoType"].as_s).to eq("Scheduled")
|
||||
|
||||
# Basic video infos
|
||||
|
||||
expect(info["title"].as_s).to eq("Home Team | PBD Podcast | Ep. 241")
|
||||
expect(info["views"].as_i).to eq(6)
|
||||
expect(info["likes"].as_i).to eq(7)
|
||||
expect(info["lengthSeconds"].as_i).to eq(0_i64)
|
||||
expect(info["published"].as_s).to eq("2023-02-28T14:00:00Z") # Unix 1677592800
|
||||
|
||||
# Extra video infos
|
||||
|
||||
expect(info["allowedRegions"].as_a).to_not be_empty
|
||||
expect(info["allowedRegions"].as_a.size).to eq(249)
|
||||
|
||||
expect(info["allowedRegions"].as_a).to contain(
|
||||
"AD", "AR", "BA", "BT", "CZ", "FO", "GL", "IO", "KE", "KH", "LS",
|
||||
"LT", "MP", "NO", "PR", "RO", "SE", "SK", "SS", "SX", "SZ", "ZW"
|
||||
)
|
||||
|
||||
expect(info["keywords"].as_a).to_not be_empty
|
||||
expect(info["keywords"].as_a.size).to eq(25)
|
||||
|
||||
expect(info["keywords"].as_a).to contain_exactly(
|
||||
"Patrick Bet-David",
|
||||
"Valeutainment",
|
||||
"The BetDavid Podcast",
|
||||
"The BetDavid Show",
|
||||
"Betdavid",
|
||||
"PBD",
|
||||
"BetDavid show",
|
||||
"Betdavid podcast",
|
||||
"podcast betdavid",
|
||||
"podcast patrick",
|
||||
"patrick bet david podcast",
|
||||
"Valuetainment podcast",
|
||||
"Entrepreneurs",
|
||||
"Entrepreneurship",
|
||||
"Entrepreneur Motivation",
|
||||
"Entrepreneur Advice",
|
||||
"Startup Entrepreneurs",
|
||||
"valuetainment",
|
||||
"patrick bet david",
|
||||
"PBD podcast",
|
||||
"Betdavid show",
|
||||
"Betdavid Podcast",
|
||||
"Podcast Betdavid",
|
||||
"Show Betdavid",
|
||||
"PBDPodcast"
|
||||
).in_any_order
|
||||
|
||||
expect(info["allowRatings"].as_bool).to be_true
|
||||
expect(info["isFamilyFriendly"].as_bool).to be_true
|
||||
expect(info["isListed"].as_bool).to be_true
|
||||
expect(info["isUpcoming"].as_bool).to be_true
|
||||
|
||||
# Related videos
|
||||
|
||||
expect(info["relatedVideos"].as_a.size).to eq(20)
|
||||
|
||||
expect(info["relatedVideos"][0]["id"]).to eq("j7jPzzjbVuk")
|
||||
expect(info["relatedVideos"][0]["author"]).to eq("Democracy Now!")
|
||||
expect(info["relatedVideos"][0]["ucid"]).to eq("UCzuqE7-t13O4NIDYJfakrhw")
|
||||
expect(info["relatedVideos"][0]["view_count"]).to eq("7576")
|
||||
expect(info["relatedVideos"][0]["short_view_count"]).to eq("7.5K")
|
||||
expect(info["relatedVideos"][0]["author_verified"]).to eq("true")
|
||||
|
||||
# Description
|
||||
|
||||
description_start_text = "PBD Podcast Episode 241. The home team is ready and at it again with the latest news, interesting topics and trending conversations on topics that matter. Try our sponsor Aura for 14 days free - https://aura.com/pbd"
|
||||
|
||||
expect(info["description"].as_s).to start_with(description_start_text)
|
||||
expect(info["shortDescription"].as_s).to start_with(description_start_text)
|
||||
|
||||
# TODO: Update mocks right before the start of PDB podcast, either on friday or saturday (time unknown)
|
||||
# expect(info["descriptionHtml"].as_s).to start_with(
|
||||
# "PBD Podcast Episode 241. The home team is ready and at it again with the latest news, interesting topics and trending conversations on topics that matter. Try our sponsor Aura for 14 days free - <a href=\"https://aura.com/pbd\">aura.com/pbd</a>"
|
||||
# )
|
||||
|
||||
# Video metadata
|
||||
|
||||
expect(info["genre"].as_s).to eq("Entertainment")
|
||||
expect(info["genreUcid"].as_s).to be_empty
|
||||
expect(info["license"].as_s).to be_empty
|
||||
|
||||
# Author infos
|
||||
|
||||
expect(info["author"].as_s).to eq("PBD Podcast")
|
||||
expect(info["ucid"].as_s).to eq("UCGX7nGXpz-CmO_Arg-cgJ7A")
|
||||
|
||||
expect(info["authorThumbnail"].as_s).to eq(
|
||||
"https://yt3.ggpht.com/61ArDiQshJrvSXcGLhpFfIO3hlMabe2fksitcf6oGob0Mdr5gztdkXxRljICUodL4iuTSrtxW4A=s48-c-k-c0x00ffffff-no-rj"
|
||||
)
|
||||
expect(info["authorVerified"].as_bool).to be_false
|
||||
expect(info["subCountText"].as_s).to eq("594K")
|
||||
end
|
||||
end
|
@ -1,35 +0,0 @@
|
||||
require "db"
|
||||
require "json"
|
||||
require "kemal"
|
||||
|
||||
require "protodec/utils"
|
||||
|
||||
require "spectator"
|
||||
|
||||
require "../src/invidious/exceptions"
|
||||
require "../src/invidious/helpers/macros"
|
||||
require "../src/invidious/helpers/logger"
|
||||
require "../src/invidious/helpers/utils"
|
||||
|
||||
require "../src/invidious/videos"
|
||||
require "../src/invidious/videos/*"
|
||||
require "../src/invidious/comments/content"
|
||||
|
||||
require "../src/invidious/helpers/serialized_yt_data"
|
||||
require "../src/invidious/yt_backend/extractors"
|
||||
require "../src/invidious/yt_backend/extractors_utils"
|
||||
|
||||
OUTPUT = File.open(File::NULL, "w")
|
||||
LOGGER = Invidious::LogHandler.new(OUTPUT, LogLevel::Off)
|
||||
|
||||
def load_mock(file) : Hash(String, JSON::Any)
|
||||
file = File.join(__DIR__, "..", "mocks", file + ".json")
|
||||
content = File.read(file)
|
||||
|
||||
return JSON.parse(content).as_h
|
||||
end
|
||||
|
||||
Spectator.configure do |config|
|
||||
config.fail_blank
|
||||
config.randomize
|
||||
end
|
@ -1,16 +0,0 @@
|
||||
# Overrides for Kemal's `content_for` macro in order to keep using
|
||||
# kilt as it was before Kemal v1.1.1 (Kemal PR #618).
|
||||
|
||||
require "kemal"
|
||||
require "kilt"
|
||||
|
||||
macro content_for(key, file = __FILE__)
|
||||
%proc = ->() {
|
||||
__kilt_io__ = IO::Memory.new
|
||||
{{ yield }}
|
||||
__kilt_io__.to_s
|
||||
}
|
||||
|
||||
CONTENT_FOR_BLOCKS[{{key}}] = Tuple.new {{file}}, %proc
|
||||
nil
|
||||
end
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue