mirror of
https://codeberg.org/ashley/poke.git
synced 2024-11-22 15:17:55 +01:00
Merge pull request 'main' (#7) from ashley/poke:main into main
Reviewed-on: https://codeberg.org/Korbs/poketube/pulls/7
This commit is contained in:
commit
0d7aa92eaa
39 changed files with 3942 additions and 790 deletions
19
.drone.yml
Normal file
19
.drone.yml
Normal file
|
@ -0,0 +1,19 @@
|
|||
kind: pipeline
|
||||
type: exec
|
||||
name: Build and Push Docker Image (Quay)
|
||||
|
||||
platform:
|
||||
os: linux
|
||||
arch: amd64
|
||||
|
||||
steps:
|
||||
- name: Build
|
||||
environment:
|
||||
QUAY_USERNAME:
|
||||
from_secret: QUAY_USERNAME
|
||||
QUAY_PASSWORD:
|
||||
from_secret: QUAY_PASSWORD
|
||||
commands:
|
||||
- echo $QUAY_PASSWORD | docker login quay.io --username $QUAY_USERNAME --password-stdin
|
||||
- docker build -t quay.io/sudovanilla/poketube .
|
||||
- docker push quay.io/sudovanilla/poketube
|
|
@ -1,4 +1,4 @@
|
|||
# Contributor Covenant Code of Conduct
|
||||
# Contributor Covenant Code of Conduct / PokeTube code of conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
|
@ -60,15 +60,15 @@ representative at an online or offline event.
|
|||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
iamashley@duck.com (E-mail) https://discord.gg/pfKSQ3pMfW (Discord server).
|
||||
iamashley@duck.com (E-mail) https://discord.gg/pfKSQ3pMfW (Discord server) https://matrix.to/#/#poke:vern.cc (matrix space) and https://rvlt.gg/poke (revolt server).
|
||||
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Additional Terms for Poketube
|
||||
|
||||
**TL;DR**: You are not allowed to edit or remove these terms from Poketube. You can't remove this file from your Poketube fork. Everyone can copy and share this document as is, but making changes is not allowed. If your chosen alternative code of conduct doesn't include provisions against hate speech, inappropriate behavior, anti-immigrant sentiments, far-right or authoritarian content, it's not allowed.
|
||||
**TL;DR**: You are encouraged not to edit or remove these terms from Poketube. While you have the freedom to make changes in your Poketube fork, if you choose to modify this document, please refrain from using the title "Poketube Code of Conduct." Everyone can copy and share this document as is, but making changes is allowed with the aforementioned condition. If your chosen alternative code of conduct doesn't include provisions against hate speech, inappropriate behavior, anti-immigrant sentiments, far-right, or authoritarian content, it's not recommended.
|
||||
|
||||
1. Definitions
|
||||
|
||||
|
@ -80,7 +80,7 @@ reporter of any incident.
|
|||
|
||||
- **Inappropriate Behavior**: Inappropriate behavior encompasses actions or expressions that create an unwelcome, hostile, or offensive environment for others, such as harassment, intimidation, or bullying.
|
||||
|
||||
- **Authoritarianism**: Authoritarianism is characterized by an emphasis on strong central authority, limited individual freedoms, and restrictions on democratic processes. Content or behavior that promotes authoritarian principles, suppresses freedom of speech, individual rights, or democratic values is strictly prohibited.
|
||||
- **Authoritarianism**: Authoritarianism is characterized by an emphasis on strong central authority, limited individual freedoms, and restrictions on democratic processes. Content or behavior that promotes authoritarian principles, suppresses freedom of speech, individual rights, or democratic values is strongly discouraged.
|
||||
|
||||
- **Protected characteristics** include attributes such as race, ethnicity, gender, religion, sexual orientation, disability, and other traits or qualities safeguarded from discrimination by relevant laws and regulations. This defines what is meant by "protected characteristics" in the context of this document.
|
||||
|
||||
|
@ -88,27 +88,24 @@ reporter of any incident.
|
|||
|
||||
NOTE: The Contributor Covenant Code of Conduct already includes provisions on some of these issues. Our intention is to provide a more defined and explicit statement regarding these prohibitions to ensure a clear and inclusive community environment.
|
||||
|
||||
YOU ARE ABSOLUTELY AND UNEQUIVOCALLY PROHIBITED FROM EDITING, REMOVING, OR ALTERING THE TERMS OF THIS FILE IN ANY WAY, SHAPE, OR FORM. FURTHERMORE, ONLY ASHLEY (THE AUTHOR) IS PERMITTED TO EDIT THIS CODE OF CONDUCT. YOU MAY NOT, UNDER ANY CIRCUMSTANCES, REMOVE THIS FILE FROM YOUR FORK OF POKETUBE. EVERY INDIVIDUAL, WITHOUT EXCEPTION, IS PERMITTED TO CREATE UNMODIFIED COPIES OF THIS DOCUMENT AND DISTRIBUTE IT AS IS; HOWEVER, THE MODIFICATION OF THIS DOCUMENT IS STRICTLY, UNMISTAKABLY, AND CATEGORICALLY FORBIDDEN. (The contact URLs within this code of conduct may be updated as needed to ensure accurate communication channels.)
|
||||
YOU ARE NOT ENCOURAGED TO EDIT, REMOVE, OR ALTER THE TERMS OF THIS FILE. However, should you choose to make changes, please avoid using the title "Poketube Code of Conduct." Removing this file from your Poketube fork is allowed. Everyone, without exception, is permitted to create unmodified copies of this document and distribute it as is; however, modifications to this document are allowed with the aforementioned condition.
|
||||
|
||||
If you do not wish to adhere to this conduct in your fork of Poketube, you have the option to utilize alternative codes of conduct instead. However, if you do not wish to adopt the alternative code of conduct, please feel free to contact us and explain your reasons for wanting to remove this file.
|
||||
It is of paramount importance to emphasize that the promotion or glorification of anti-immigrant sentiments, the alignment with far-right ideologies, Islamophobia, or any form of religious discrimination is strongly discouraged within the scope of Poketube. We maintain a stance against such content, which includes material that discriminates against immigrants, promotes hatred or hostility towards religious groups, or actively supports extremist beliefs associated with far-right ideologies. This stance is encouraged and non-binding.
|
||||
|
||||
It is of paramount importance to emphasize that the promotion or glorification of anti-immigrant sentiments, the alignment with far-right ideologies, Islamophobia, or any form of religious discrimination is entirely and unequivocally prohibited within the scope of Poketube. We maintain a zero-tolerance stance on such content, which includes any material that discriminates against immigrants, promotes hatred or hostility towards religious groups, or actively supports extremist beliefs associated with far-right ideologies. This stance is unwavering and non-negotiable.
|
||||
We believe in fostering an environment that is inclusive, respectful, and free from discrimination or the promotion of extremist ideologies. As such, any content found in violation of this encouragement will be addressed promptly and appropriately.
|
||||
|
||||
We believe in fostering an environment that is inclusive, respectful, and free from discrimination or the promotion of extremist ideologies. As such, any content found in violation of this prohibition will be addressed promptly and appropriately.
|
||||
|
||||
THE CLARITY AND FORCE OF THIS STATEMENT ARE INTENDED TO LEAVE NO ROOM FOR AMBIGUITY: ANTI-IMMIGRANT SENTIMENTS, FAR-RIGHT IDEOLOGIES, ISLAMOPHOBIA, RELIGIOUS DISCRIMINATION, MISOGYNY, AND SEXISM ARE STRICTLY OFF-LIMITS AND WILL NOT BE TOLERATED WITHIN OUR COMMUNITY. OUR COMMITMENT TO MAINTAINING A RESPECTFUL AND INCLUSIVE ATMOSPHERE EXTENDS TO ALL, REGARDLESS OF THEIR BACKGROUND, BELIEFS, OR IDENTITY.
|
||||
THE CLARITY AND FORCE OF THIS STATEMENT ARE INTENDED TO ENCOURAGE CLEAR GUIDELINES: ANTI-IMMIGRANT SENTIMENTS, FAR-RIGHT IDEOLOGIES, ISLAMOPHOBIA, RELIGIOUS DISCRIMINATION, MISOGYNY, AND SEXISM ARE STRONGLY DISCOURAGED AND NOT PREFERRED WITHIN OUR COMMUNITY. OUR HOPE IS TO MAINTAIN A RESPECTFUL AND INCLUSIVE ATMOSPHERE FOR ALL, REGARDLESS OF THEIR BACKGROUND, BELIEFS, OR IDENTITY.
|
||||
|
||||
These terms may be subject to change, and any updates will be communicated to the Poketube community. Changes to these terms will be communicated to users.
|
||||
|
||||
**3. Application of GNU Kind Communication Policy**
|
||||
|
||||
These terms also apply the principles outlined in the [GNU Kind Communication Policy](https://www.gnu.org/philosophy/kind-communication.html), which encourage respectful and inclusive communication within the Poketube community.
|
||||
These terms also align with the principles outlined in the [GNU Kind Communication Policy](https://www.gnu.org/philosophy/kind-communication.html), which encourage respectful and inclusive communication within the Poketube community.
|
||||
|
||||
It is crucial to note that we respect the diverse opinions and beliefs of our users.
|
||||
|
||||
***Additional terms end lol***
|
||||
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
|
|
|
@ -25,7 +25,7 @@ RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg -
|
|||
RUN echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_18.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get -y install nodejs
|
||||
RUN apt-get -y install nodejs npm
|
||||
|
||||
# Install Packages
|
||||
RUN npm install
|
||||
|
|
29
README.md
29
README.md
|
@ -1,12 +1,28 @@
|
|||
# see https://codeberg.org/Ashley/poke/issues/59 if you are having problems using poke
|
||||
|
||||
<h1 align="center">
|
||||
<a href="https://poketube.fun/watch?v=9sJUDx7iEJw&quality=medium&=sjohgteojgytrueugtye4jhtytjrjnyıı">
|
||||
<img src="https://poketube.fun/css/logo-poke.svg" width="400">
|
||||
<a href="http://www.defectivebydesign.org/drm-free">
|
||||
<img src="https://static.fsf.org/dbd/label/DRM-free%20label%20120.en.png"
|
||||
alt="DefectiveByDesign.org"
|
||||
width="65" height="65" border="0" align="middle" /></a>
|
||||
</a>
|
||||
<p>The Ultimate Privacy App</p>
|
||||
</h1>
|
||||
|
||||
<div align="center">
|
||||
|
||||
<span> Be Anonymous watching epic videos, searching thingys on the interwebs and listening to music on poke - the free privacy front end!</span></div>
|
||||
<span> Be Anonymous watching epic videos, searching thingys on the interwebs and listening to music on poke - the free privacy front end!</span>
|
||||
|
||||
<span>"Since you work on poke, Are you in touch with its lead developer "Jose marchasi"? <br>
|
||||
-RMS
|
||||
|
||||
Stallman though poke was GNU poke lmaoooo
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
<div align="center">
|
||||
|
||||
[Welcome!](#welcome) | [Features](#features) | [No non-free codec needed](#no-non-free-codec-needed-3) | [Hosting Poke~](#hosting-poketube) | [Poke community!](#poketube-community) | [The Legal Stuff (boring tbh)](#the-legal-stuff-boring-tbh)
|
||||
|
@ -27,7 +43,7 @@
|
|||
|
||||
## Welcome!
|
||||
|
||||
This is the source code of PokeTube, the privacy-friendly youtube front-end built with the InnerTube API!
|
||||
This is the source code of Poke (formerly PokeTube), the privacy-friendly youtube front-end built with the InnerTube API!
|
||||
|
||||
|
||||
<h1>Features</h1>
|
||||
|
@ -129,11 +145,16 @@ The port can be changed with the config file you downloaded, just change the `se
|
|||
see [here](https://codeberg.org/Ashley/poke/src/branch/main/january) :3
|
||||
just uhh change the url in config.json to ur image proxy
|
||||
|
||||
## PokeTube community!
|
||||
## Poke community!
|
||||
|
||||
Join the community on [revolt](https://rvlt.gg/poketube) :3
|
||||
Join the community on [revolt](https://rvlt.gg/poketube) or [matrix](https://matrix.to/#/#poke:vern.cc) :3
|
||||
|
||||
## The Legal Stuff (boring tbh)
|
||||
the main parts of the project is Under GPL-3.0-OR-LATER :3
|
||||
|
||||
see the each sections LICENSE tho!!
|
||||
Copyleft 2021-202x Poke Project
|
||||
|
||||
|
||||
[Code Of conduct](https://codeberg.org/Ashley/poketube/src/branch/main/CODE_OF_CONDUCT.md)
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
"invapi": "https://invid-api.poketube.fun/api/v1",
|
||||
"dislikes": "https://returnyoutubedislikeapi.com/votes?videoId=",
|
||||
"invchannel": "https://invid-api.poketube.fun/api/v1",
|
||||
"p_url":"https://p.poketube.fun",
|
||||
"media_proxy": "https://image-proxy.poketube.fun",
|
||||
"cacher_max_age": "864000",
|
||||
"enablealwayshttps": false,
|
||||
|
|
127
css/app.js
127
css/app.js
|
@ -98,7 +98,7 @@ function fadeInElements() {
|
|||
|
||||
window.addEventListener('scroll', fadeInElements);
|
||||
document.addEventListener('fullscreenchange', fadeInElements);
|
||||
setInterval(fadeInElements, 500);
|
||||
setInterval(fadeInElements, 100);
|
||||
|
||||
function jumpToTime(e) {
|
||||
e.preventDefault();
|
||||
|
@ -202,30 +202,100 @@ function fetchUrls(urls) {
|
|||
});
|
||||
}
|
||||
|
||||
/*
|
||||
// Fetch channel URLs
|
||||
const channelUrls = document.querySelectorAll('a[href*="/channel?id="]');
|
||||
fetchUrls(channelUrls);
|
||||
function anondocumenttitle(message, times) {
|
||||
var hash = CryptoJS.SHA256(message);
|
||||
|
||||
// Fetch download URLs
|
||||
const downloadUrls = document.querySelectorAll('a[href*="/download?v="]');
|
||||
fetchUrls(downloadUrls);
|
||||
return hash.toString(CryptoJS.enc.Hex);
|
||||
}
|
||||
|
||||
if(navigator.globalPrivacyControl) {
|
||||
var gpcValue = navigator?.globalPrivacyControl
|
||||
} else {
|
||||
var gpcValue = false
|
||||
}
|
||||
|
||||
if (location.hostname === "poketube.fun") {
|
||||
if (typeof Ashley === "undefined") {
|
||||
var Ashley = {};
|
||||
}
|
||||
Ashley.dntEnabled = function (dnt, ua) {
|
||||
"use strict";
|
||||
var dntStatus =
|
||||
dnt ||
|
||||
navigator.doNotTrack ||
|
||||
window.doNotTrack ||
|
||||
navigator.msDoNotTrack;
|
||||
var userAgent = ua || navigator.userAgent;
|
||||
var anomalousWinVersions = [
|
||||
"Windows NT 6.1",
|
||||
"Windows NT 6.2",
|
||||
"Windows NT 6.3",
|
||||
];
|
||||
var fxMatch = userAgent.match(/Firefox\/(\d+)/);
|
||||
var ieRegEx = /MSIE|Trident/i;
|
||||
var isIE = ieRegEx.test(userAgent);
|
||||
var platform = userAgent.match(/Windows.+?(?=;)/g);
|
||||
if (isIE && typeof Array.prototype.indexOf !== "function") {
|
||||
return false;
|
||||
} else if (fxMatch && parseInt(fxMatch[1], 10) < 32) {
|
||||
dntStatus = "Unspecified";
|
||||
} else if (
|
||||
isIE &&
|
||||
platform &&
|
||||
anomalousWinVersions.indexOf(platform.toString()) !== -1
|
||||
) {
|
||||
dntStatus = "Unspecified";
|
||||
} else {
|
||||
dntStatus = { 0: "Disabled", 1: "Enabled" }[dntStatus] || "Unspecified";
|
||||
}
|
||||
return dntStatus === "Enabled" ? true : false;
|
||||
};
|
||||
// only load if DNT is not enabled
|
||||
if(!gpcValue) {
|
||||
if (Ashley && !Ashley.dntEnabled()) {
|
||||
var _paq = (window._paq = window._paq || []);
|
||||
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
|
||||
_paq.push([
|
||||
"setDocumentTitle",
|
||||
anondocumenttitle(document.domain, 5) +
|
||||
"/" +
|
||||
anondocumenttitle(document.title, 5),
|
||||
]);
|
||||
_paq.push(["setDoNotTrack", true]);
|
||||
_paq.push(["disableCookies"]);
|
||||
_paq.push(["trackPageView"]);
|
||||
_paq.push(["enableLinkTracking"]);
|
||||
(function () {
|
||||
var u = "//data.poketube.fun/";
|
||||
_paq.push(["setTrackerUrl", u + "matomo.php"]);
|
||||
_paq.push(["setSiteId", "2"]);
|
||||
var d = document,
|
||||
g = d.createElement("script"),
|
||||
s = d.getElementsByTagName("script")[0];
|
||||
g.async = true;
|
||||
g.src = u + "matomo.js";
|
||||
s.parentNode.insertBefore(g, s);
|
||||
})();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fetch videos urls
|
||||
const urls = document.querySelectorAll('a[href*="/watch?v="]');
|
||||
fetchUrls(urls);
|
||||
*/
|
||||
var popupMenu = document.getElementById("popupMenu");
|
||||
var loopOption = document.getElementById("loopOption");
|
||||
var speedOption = document.getElementById("speedOption");
|
||||
|
||||
video.addEventListener("contextmenu", function(event) {
|
||||
|
||||
video.addEventListener("contextmenu", function(event) {
|
||||
// Check if the video is in fullscreen mode
|
||||
if (!document.fullscreenElement && !document.webkitFullscreenElement && !document.mozFullScreenElement && !document.msFullscreenElement) {
|
||||
event.preventDefault();
|
||||
|
||||
popupMenu.style.display = "block";
|
||||
popupMenu.style.left = event.pageX + "px";
|
||||
popupMenu.style.top = event.pageY + "px";
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Hide the popup menu when clicking outside of it
|
||||
window.addEventListener("click", function(event) {
|
||||
|
@ -234,13 +304,32 @@ fetchUrls(urls);
|
|||
}
|
||||
});
|
||||
|
||||
var loopedIndicator = document.getElementById("loopedIndicator");
|
||||
|
||||
loopedIndicator.style.display = "none"; // Initially hide the indicator
|
||||
|
||||
loopOption.addEventListener("click", function() {
|
||||
video.loop = !video.loop;
|
||||
if (video.loop) {
|
||||
alert("Looped!");
|
||||
var looped = video.loop;
|
||||
video.loop = !looped;
|
||||
|
||||
|
||||
// Update the looped indicator popup
|
||||
var displaySpecialText = Math.random() < 0.5;
|
||||
|
||||
// Update the looped indicator popup
|
||||
if (displaySpecialText) {
|
||||
var specialText = looped ? "Unlooped >.<" : "Looped~ :3 >~<";
|
||||
loopedIndicator.textContent = specialText;
|
||||
} else {
|
||||
alert("unlooped!")
|
||||
loopedIndicator.textContent = looped ? "Unlooped!" : "Looped!";
|
||||
}
|
||||
loopedIndicator.style.display = "block";
|
||||
|
||||
// Hide the indicator after 2 seconds
|
||||
setTimeout(function() {
|
||||
loopedIndicator.style.display = "none";
|
||||
}, 2000);
|
||||
|
||||
});
|
||||
|
||||
speedOption.addEventListener("click", function() {
|
||||
|
@ -263,4 +352,6 @@ fetchUrls(urls);
|
|||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
const GoogleTranslateEndpoint = "https://translate.google.com/_/TranslateWebserverUi/data/batchexecute?rpcids=MkEWBc&rt=c"
|
||||
// @license-end
|
|
@ -1258,15 +1258,6 @@ nav .right img {
|
|||
border-radius: 50%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "PokeTube Flex";
|
||||
src: url("https://p.poketube.fun/https://cdn.glitch.global/43b6691a-c8db-41d4-921c-8cf6aa0d9108/robotoflex.ttf?v=1668343428681");
|
||||
font-style: normal;
|
||||
font-stretch: 1% 800%;
|
||||
font-weight: 1 1000;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
.video > .thumbnail > .video-length {
|
||||
font-size: smaller;
|
||||
background-color: #0008;
|
||||
|
|
BIN
css/favicon.ico
Normal file
BIN
css/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 91 KiB |
BIN
css/poke-chan-outfit-a.png
Normal file
BIN
css/poke-chan-outfit-a.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 121 KiB |
BIN
css/poke-screnshot-a.png
Normal file
BIN
css/poke-screnshot-a.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 515 KiB |
|
@ -19,6 +19,58 @@
|
|||
|
||||
*/
|
||||
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Montserrat';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-stretch: 100%;
|
||||
src: url(https://p.poketube.fun/https://fonts.bunny.net/montserrat/files/montserrat-latin-500-normal.woff2) format('woff2'), url(https://p.poketube.fun/https://fonts.bunny.net/montserrat/files/montserrat-latin-500-normal.woff) format('woff');
|
||||
unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
|
||||
}
|
||||
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Montserrat';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-stretch: 100%;
|
||||
src: url(https://p.poketube.fun/https://fonts.bunny.net/montserrat/files/montserrat-cyrillic-500-normal.woff2) format('woff2'), url(https://p.poketube.fun/https://fonts.bunny.net/montserrat/files/montserrat-cyrillic-500-normal.woff) format('woff');
|
||||
unicode-range: U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116;
|
||||
}
|
||||
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Montserrat';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-stretch: 100%;
|
||||
src: url(https://p.poketube.fun/https://fonts.bunny.net/montserrat/files/montserrat-latin-ext-500-normal.woff2) format('woff2'), url(https://p.poketube.fun/https://fonts.bunny.net/montserrat/files/montserrat-latin-ext-500-normal.woff) format('woff');
|
||||
unicode-range: U+0100-02AF,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF;
|
||||
}
|
||||
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Montserrat';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-stretch: 100%;
|
||||
src: url(https://p.poketube.fun/https://fonts.bunny.net/montserrat/files/montserrat-vietnamese-500-normal.woff2) format('woff2'), url(https://p.poketube.fun/https://fonts.bunny.net/montserrat/files/montserrat-vietnamese-500-normal.woff) format('woff');
|
||||
unicode-range: U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB;
|
||||
}
|
||||
|
||||
/* cyrillic-ext */
|
||||
@font-face {
|
||||
font-family: 'Montserrat';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-stretch: 100%;
|
||||
src: url(https://p.poketube.fun/https://fonts.bunny.net/montserrat/files/montserrat-cyrillic-ext-500-normal.woff2) format('woff2'), url(https://p.poketube.fun/https://fonts.bunny.net/montserrat/files/montserrat-cyrillic-ext-500-normal.woff) format('woff');
|
||||
unicode-range: U+0460-052F,U+1C80-1C88,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F;
|
||||
}
|
||||
|
||||
|
||||
|
||||
:root {
|
||||
/* text */
|
||||
--text-link: #0ab7f0;
|
||||
|
@ -200,22 +252,29 @@ a.avatar {
|
|||
.recommended-list {
|
||||
background-color: var(--div-prim-bg);
|
||||
border-radius: 1.5em;
|
||||
/* padding-right: 24px; */
|
||||
margin: 10px;
|
||||
margin-top: 0px;
|
||||
margin-left: 0px;
|
||||
margin-top: 0;
|
||||
margin-left: 0;
|
||||
height: -moz-fit-content;
|
||||
height: fit-content;
|
||||
justify-self: center;
|
||||
margin-right: -0.9em;
|
||||
/* width: min-content;*/
|
||||
/* justify-self: center; */
|
||||
margin-right: -.9em;
|
||||
border: var(--div-border-color);
|
||||
border-style: solid;
|
||||
max-width: 371px;
|
||||
width: max-content;
|
||||
width: 20.9em;
|
||||
}
|
||||
|
||||
.video-views {
|
||||
white-space: nowrap;
|
||||
white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */
|
||||
white-space: -pre-wrap; /* Opera 4-6 */
|
||||
white-space: -o-pre-wrap; /* Opera 7 */
|
||||
white-space: pre-wrap; /* css-3 */
|
||||
word-wrap: break-word; /* Internet Explorer 5.5+ */
|
||||
white-space: -webkit-pre-wrap; /* Newer versions of Chrome/Safari*/
|
||||
word-break: break-all;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.video-info-panel.gradient {
|
||||
|
@ -234,7 +293,6 @@ a.avatar {
|
|||
font-weight: 1000;
|
||||
font-stretch: ultra-expanded;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
line-clamp: 3;
|
||||
|
@ -402,7 +460,7 @@ a.avatar {
|
|||
border-radius: 4px;
|
||||
word-break: break-all;
|
||||
white-space: nowrap;
|
||||
font-family: ubuntu, sans-serif;
|
||||
font-family: "Montserrat", sans-serif;
|
||||
}
|
||||
|
||||
.new-button {
|
||||
|
@ -513,7 +571,7 @@ a.avatar {
|
|||
margin: 0;
|
||||
width: 300px;
|
||||
border-radius: 8px;
|
||||
font-family: ubuntu, sans-serif;
|
||||
font-family: "Montserrat", sans-serif;
|
||||
box-shadow: var(--border-color) 0 0 5px;
|
||||
background-color: var(--context-menu-background);
|
||||
}
|
||||
|
@ -523,10 +581,12 @@ a.avatar {
|
|||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 0 16px;
|
||||
padding-left: 16px;
|
||||
height: 40px;
|
||||
column-gap: 16px;
|
||||
color: var(--text-primary);
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.dropdown__item:hover {
|
||||
|
@ -679,7 +739,7 @@ a.new-button:hover {
|
|||
border-radius: 10px;
|
||||
height: fit-content;
|
||||
padding: 10px;
|
||||
font-family: ubuntu, sans-serif;
|
||||
font-family: "ubuntu", sans-serif;
|
||||
margin-left: -11em;
|
||||
width: 43em;
|
||||
position: absolute;
|
||||
|
@ -779,7 +839,6 @@ object-fit:none;
|
|||
font-stretch: expanded;
|
||||
overflow:hidden;
|
||||
font-family: var(--text-font-primary);
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: auto;
|
||||
max-width: 21em;
|
||||
|
@ -794,7 +853,9 @@ object-fit:none;
|
|||
}
|
||||
|
||||
.video > .info {
|
||||
font-family: Ubuntu, sans-serif;
|
||||
font-family: "Montserrat", sans-serif;
|
||||
font-weight: 500;
|
||||
|
||||
}
|
||||
|
||||
/* Width */
|
||||
|
|
|
@ -94,8 +94,3 @@ a {
|
|||
</body>
|
||||
</html>
|
||||
|
||||
<script>
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.register('service-worker.js');
|
||||
}
|
||||
</script>
|
135
html/apps.ejs
Normal file
135
html/apps.ejs
Normal file
|
@ -0,0 +1,135 @@
|
|||
<!--
|
||||
This Source Code Form is subject to the terms of the GNU General Public License:
|
||||
|
||||
Copyright (C) 2021-2024 PokeTube (https://codeberg.org/Ashley/poketube)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Poke Apps</title>
|
||||
<meta content="▶▶ Poke - The Ultimate privacy App!" property=og:title>
|
||||
<meta content="Poke is more then a youtueb front end - see all the stuff in poke!! :3" property=twitter:description>
|
||||
<meta content="https://cdn.glitch.global/d68d17bb-f2c0-4bc3-993f-50902734f652/aa70111e-5bcd-4379-8b23-332a33012b78.image.png?v=1701898829884" property="og:image" />
|
||||
<meta content="summary_large_image" name="twitter:card" />
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
<link href="/css/yt-ukraine.svg?v=3" rel="icon" />
|
||||
<link href="https://p.poketube.fun/https://site-assets.fontawesome.com/releases/v6.1.1/css/all.css" rel="stylesheet" />
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: "PokeTube Flex";
|
||||
src: url("https://p.poketube.fun/https://cdn.glitch.global/43b6691a-c8db-41d4-921c-8cf6aa0d9108/robotoflex.ttf?v=1668343428681");
|
||||
font-style: normal;
|
||||
font-stretch: 1% 800%;
|
||||
font-display: swap;
|
||||
}
|
||||
body {
|
||||
font-family: "PokeTube flex", sans-serif;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
background-image: radial-gradient(
|
||||
circle,
|
||||
#231638,
|
||||
#2b160e,
|
||||
#09250e,
|
||||
#0f132b
|
||||
);
|
||||
animation: gradient 64s ease infinite;
|
||||
background-size: 400% 400%;
|
||||
min-height: 100vh;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
h1 {
|
||||
margin-top: 0;
|
||||
font-weight: 1000;
|
||||
font-stretch: ultra-expanded;
|
||||
font-family: "Poketube flex";
|
||||
color: #fff;
|
||||
}
|
||||
@keyframes gradient {
|
||||
0% {
|
||||
background-position: 0 50%;
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 50%;
|
||||
}
|
||||
100% {
|
||||
background-position: 0 50%;
|
||||
}
|
||||
}
|
||||
.poke-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 16px;
|
||||
padding: 16px;
|
||||
background: #1e1e1e;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.poke-header {
|
||||
text-align: center;
|
||||
padding: 16px;
|
||||
background: #212121;
|
||||
color: #fff;
|
||||
border-radius: 8px 8px 0 0;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
grid-column: span 4;
|
||||
}
|
||||
.subtext {
|
||||
color: #b0b0b0;
|
||||
margin-top: 8px;
|
||||
}
|
||||
.poke-app-btn {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
background: #2c2c2c;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
transition: background 0.3s ease, color 0.3s ease, box-shadow 0.3s ease;
|
||||
}
|
||||
.poke-app-btn:hover {
|
||||
background: #404040;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
.poke-app-btn i {
|
||||
margin-bottom: 8px;
|
||||
font-size: 24px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="poke-container">
|
||||
<div class="poke-header">
|
||||
<h1>Moar from Poke</h1>
|
||||
<p class="subtext">Poke is not just a youtube front end - its moar!!</p>
|
||||
</div>
|
||||
|
||||
<a href="/game-hub" class="poke-app-btn"><i class="fa-light fa-gamepad"></i>Games</a>
|
||||
<a href="/web" class="poke-app-btn"><i class="fa-light fa-search"></i>Web Search</a>
|
||||
<a href="/translate" class="poke-app-btn"><i class="fa-light fa-language"></i>Translate</a>
|
||||
<a href="/map" class="poke-app-btn"><i class="fa-light fa-map-marker-alt"></i>Maps</a>
|
||||
<a href="/app" class="poke-app-btn"><i class="fa-light fa-play"></i>PokeTube</a>
|
||||
<a href="/settings" class="poke-app-btn"><i class="fa-light fa-cogs"></i>Settings</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
368
html/channel.ejs
368
html/channel.ejs
|
@ -1,9 +1,9 @@
|
|||
<% try { %>
|
||||
<% try { %>
|
||||
|
||||
<!--
|
||||
This Source Code Form is subject to the terms of the GNU General Public License:
|
||||
|
||||
Copyright (C) 2021-2023 POKETUBE (https://codeberg.org/Ashley/poketube)
|
||||
Copyright (C) 2021-2024 POKETUBE (https://codeberg.org/Ashley/poketube)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -19,26 +19,24 @@
|
|||
along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
-->
|
||||
<!DOCTYPE html><html><head>
|
||||
<!-- 🐷 🎗️ -->
|
||||
|
||||
<% if (ID === "UCFAiFyGs6oDiF1Nf-rRJpZA") { %>
|
||||
<title>Technoblade Never Dies! - PokeTube</title>
|
||||
<% } %>
|
||||
<title><%=j.Channel?.Metadata.Name%> - PokeTube</title>
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
<link href=css/yt-ukraine.svg rel=icon>
|
||||
<link href="css/yt-ukraine.svg" rel=icon>
|
||||
<meta content=website property=og:type>
|
||||
<link rel="alternate" type="application/rss+xml" href="/feeds/videos.xml?channel_id=<%=ID%>">
|
||||
<meta content="<%=j.Channel?.Metadata.Name%> - PokeTube" property=og:title>
|
||||
<link href=/css/yt-ukraine.svg?v=6 rel=icon>
|
||||
|
||||
|
||||
<meta content="<%- cinv.description %>" property=twitter:description>
|
||||
<meta name="darkreader-lock"> <!-- tells dark reader that the site has a dark theme and to turn itself off -->
|
||||
<% if (j.Channel?.Metadata.Banners.Thumbnail) { %>
|
||||
|
||||
<meta content="<%=j.Channel?.Metadata?.Banners.Thumbnail[2].$t%>" property=og:image>
|
||||
<% } %>
|
||||
|
||||
<meta content=summary_large_image name=twitter:card>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<style>
|
||||
* {
|
||||
color:#fff
|
||||
|
@ -310,7 +308,56 @@ text-transform:uppercase;
|
|||
</style>
|
||||
|
||||
<% if(!isMobile) { %>
|
||||
<noscript>
|
||||
<style>
|
||||
#search {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.subscribe-button.needs-js {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.subscribe-button {
|
||||
margin-right: 6px !important;
|
||||
margin-top: 10px !important;
|
||||
margin-left: -4px !important;
|
||||
}
|
||||
</style>
|
||||
</noscript>
|
||||
<style>
|
||||
.channel-info > .avatar > img {
|
||||
width: auto;
|
||||
height: auto;
|
||||
max-height: 150px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1230px) {
|
||||
.channel-info > .avatar > img {
|
||||
margin-left: 1em;
|
||||
}
|
||||
.name {
|
||||
margin-left: 5em !important;
|
||||
}
|
||||
}
|
||||
|
||||
.subscribe-button:hover {
|
||||
animation: animateBg 2s infinite linear;
|
||||
background-color: #fff;
|
||||
background-image: linear-gradient(90deg,#da3287,#ffde5e,#da3287,#ffde5e);
|
||||
background-size: 300% 100%;
|
||||
box-shadow: 0 3px 14px #000;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@keyframes animateBg {
|
||||
0% {
|
||||
background-position:0 0
|
||||
}
|
||||
100% {
|
||||
background-position:100% 0
|
||||
}
|
||||
}
|
||||
.video:hover{
|
||||
border:solid;
|
||||
}
|
||||
|
@ -327,6 +374,30 @@ text-transform:uppercase;
|
|||
}
|
||||
.subs {
|
||||
margin: 0.6em;text-align: left;margin-left: 0px;margin-top: -1em;font-family: "PokeTube flex";font-weight: 1000;font-stretch: ultra-expanded;
|
||||
}
|
||||
#popup-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background-color: #111;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
z-index: 1;
|
||||
width: 45em;
|
||||
height: 24em;
|
||||
overflow:auto;
|
||||
}
|
||||
|
||||
#close-btn {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
font-size: 18px;
|
||||
color: #555;
|
||||
}
|
||||
.video-grid {
|
||||
display: flex;
|
||||
|
@ -404,6 +475,8 @@ color:#ea9999 !important;
|
|||
.channel-info{
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
|
||||
.sticky-top {
|
||||
position: sticky;
|
||||
top: 0px;
|
||||
|
@ -494,10 +567,8 @@ color:#ea9999 !important;
|
|||
<button class="btn btn-success" type="submit"><i class="fa-light fa-search"></i></button>
|
||||
|
||||
</form>
|
||||
<img src="https://search-metrics.poketube.fun/t/rep.gif" style="border:0;width: 0;visibility: hidden;">
|
||||
|
||||
</div>
|
||||
<img src="https://search-metrics.poketube.fun/t/rep.gif" style="border:0;width: 0;visibility: hidden;">
|
||||
|
||||
</div>
|
||||
<div class="right">
|
||||
|
@ -514,6 +585,20 @@ color:#ea9999 !important;
|
|||
|
||||
|
||||
<% } %>
|
||||
<% if (!isMobile) { %>
|
||||
|
||||
<div onclick="closePopup()" id="popup-container">
|
||||
<div id="close-btn" onclick="closePopup()">X</div>
|
||||
|
||||
<% if (cinv.descriptionHtml) { %>
|
||||
|
||||
|
||||
<p style="color:#fff;margin-left: 10px;font-weight: bold;"><%-cinv.descriptionHtml%></p>
|
||||
</div>
|
||||
|
||||
<% } %>
|
||||
<% } %>
|
||||
|
||||
|
||||
|
||||
<% if (isMobile) { %>
|
||||
|
@ -555,56 +640,50 @@ color:#ea9999 !important;
|
|||
|
||||
<img src="https://p.poketube.fun/<%=j.Channel?.Metadata.Banners.Thumbnail[2].$t%>">
|
||||
<% } %>
|
||||
<div class="channel-info" >
|
||||
|
||||
<div class="channel-info" style="margin-bottom: 2em;margin-left:3em">
|
||||
<a href="/avatars/<%=j.Channel?.Metadata.Avatars.Thumbnail?.$t.replace("https://yt3.googleusercontent.com/", "")%>" class="avatar">
|
||||
<img src="/avatars/<%=j.Channel?.Metadata.Avatars.Thumbnail?.$t.replace("https://yt3.googleusercontent.com/", "")%>" alt="Channel Avatar">
|
||||
</a>
|
||||
|
||||
|
||||
<% if (cinv?.authorVerified) { %>
|
||||
<style>
|
||||
|
||||
.name {
|
||||
border:solid 2.1px #df80ff;
|
||||
border:solid 1px #df80ff;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
<% } %>
|
||||
|
||||
<div class="name" style="background: #333;border-radius: 12px;padding: 9px;height: 6em;">
|
||||
<div class="name" style="background: #333;border-radius: 12px;padding: 17px;height: 7em;margin-left: 4em;margin-top: 7px;gap: 3px;">
|
||||
<p style="font-family:PokeTube Flex,sans-serif;font-weight:1000;font-stretch: ultra-expanded;margin-top: 16px;margin-bottom: 15px;"><%=j.Channel?.Metadata.Name%>
|
||||
|
||||
<span style="background: #0005;padding: 3px;padding-top: 2.5px !important;display: inline-flex;border-radius: 3px;">
|
||||
<% if (cinv?.authorVerified) { %>
|
||||
<% if (cinv?.isFamilyFriendly) { %>
|
||||
<% if (cinv?.authorVerified) { %><span style="background: #0005;padding: 3px;padding-top: 2.5px !important;display: inline-flex;border-radius: 3px;">
|
||||
|
||||
<i class="fa-solid fa-badge-check" style="width: 18px;margin-right:7px" title="Verified Channel"></i>
|
||||
|
||||
<i class="fa-solid fa-badge-check" style="width: 18px;margin-right:1px" title="Verified Channel"></i>
|
||||
|
||||
</span>
|
||||
<% } %>
|
||||
<% if (!cinv.isFamilyFriendly) { %>
|
||||
<i class="fa-solid fa-badge-check" style="width: 18px" title="Verified Channel"></i>
|
||||
|
||||
<% } %>
|
||||
|
||||
<% } %>
|
||||
<% if (cinv?.isFamilyFriendly) { %>
|
||||
|
||||
<img src="https://cdn.glitch.global/d68d17bb-f2c0-4bc3-993f-50902734f652/bbf42a35-8976-43a5-a7a2-72a81d9da7ce.image.png?v=1692301199470" style="width: 18px;" title="In Youtube kids" >
|
||||
<% } %>
|
||||
|
||||
</span> </p>
|
||||
<p style="margin-bottom: -11px;" class="subs"><%=subs%> subscribers</p>
|
||||
<span style="font-size: 10px;color: gray;">@<%- cinv.authorId %>@youtube.com</span>
|
||||
</p>
|
||||
<p style="margin-bottom: -17px;" class="subs"><%=subs%> subscribers</p>
|
||||
<p style="padding:0;font-weight:bold;max-inline-size: 37em;display: -webkit-box;-webkit-line-clamp: 3;-webkit-box-orient: vertical;">
|
||||
|
||||
<% try { %>
|
||||
<%- getFirstLine(cinv.description).slice(0, 60) %>
|
||||
<a href="/channel?id=<%= ID %>&tab=about">
|
||||
<%- getFirstLine(cinv.description).slice(0, 60) || "More from this channel (soon)"%>
|
||||
<a href="/channel?id=<%=ID%>&tab=about&legacy=true" id="popup-trigger">
|
||||
<% } catch (error) { %>
|
||||
<!-- Handle the error here, if it occurs -->
|
||||
<p>Error: <%= error.message %></p>
|
||||
<% } %>
|
||||
|
||||
<i class="fa-thin fa-angle-right"></i></a><br><button class="subscribe-button " style="text-decoration: none;margin-right:3px !important;"> <a style="color: black;
|
||||
<i class="fa-thin fa-angle-right"></i></a><br><button class="subscribe-button needs-js" style="text-decoration: none;margin-right:6px !important;margin-top: 10px !important;margin-left: -4px !important;"> <a style="color: black;
|
||||
white-space: nowrap;text-decoration: none;" id="sub">Suscribe</a></button><button class="subscribe-button " style="text-decoration: none;"> <a style="color: black;
|
||||
white-space: nowrap;text-decoration: none;" href="/feeds/videos.xml?channel_id=<%=ID%>">Rss feed </a></button>
|
||||
|
||||
|
@ -652,8 +731,62 @@ white-space: nowrap;text-decoration: none;" href="/feeds/videos.xml?channel_id=<
|
|||
<% } %>
|
||||
<% } %>
|
||||
|
||||
<% if (Array.isArray(playlist?.playlists)) { %>
|
||||
|
||||
<% if (playlist.playlists.length != "0") { %>
|
||||
|
||||
<a href="/channel?id=<%=ID%>&tab=playlist" class="tab" style="color:pink">Playlists</a>
|
||||
<% } %>
|
||||
<% } %>
|
||||
|
||||
|
||||
<% } %>
|
||||
|
||||
<% if (tab === "playlist") { %>
|
||||
|
||||
<a href="/channel?id=<%=ID%>" class="tab" style="color:#cfe2f3;">Videos</a>
|
||||
|
||||
<% if (Array.isArray(shorts?.videos)) { %>
|
||||
<% if (shorts.videos[0]) { %>
|
||||
<% if (turntomins(shorts.videos[0].lengthSeconds) != "aN:aN" ) { %>
|
||||
|
||||
|
||||
<a href="/channel?id=<%=ID%>&tab=shorts" class="tab shr">Shorts</a>
|
||||
<% } %>
|
||||
<% } %>
|
||||
|
||||
<% } %>
|
||||
|
||||
<% if (Array.isArray(stream?.videos)) { %>
|
||||
<% if (stream.videos[0]) { %>
|
||||
|
||||
<% if (turntomins(stream.videos[0].lengthSeconds) != "aN:aN" ) { %>
|
||||
|
||||
<a href="/channel?id=<%=ID%>&tab=live" class="tab" style="color:#d9ead3;">Live</a>
|
||||
<% } %>
|
||||
<% } %>
|
||||
|
||||
<% } %>
|
||||
|
||||
<% if (Array.isArray(c?.comments)) { %>
|
||||
|
||||
<% if (c.comments.length != "0") { %>
|
||||
|
||||
<a href="/channel?id=<%=ID%>&tab=community" class="tab" style="color:pink">Community</a>
|
||||
<% } %>
|
||||
<% } %>
|
||||
|
||||
<% if (Array.isArray(playlist?.playlists)) { %>
|
||||
|
||||
<% if (playlist.playlists.length != "0") { %>
|
||||
|
||||
<a href="/channel?id=<%=ID%>&tab=playlist" class="tab active" style="color:pink">Playlists</a>
|
||||
<% } %>
|
||||
<% } %>
|
||||
|
||||
|
||||
<% } %>
|
||||
|
||||
<% if (tab === "about") { %>
|
||||
|
||||
<a href="/channel?id=<%=ID%>" class="tab" style="color:#cfe2f3;">Videos</a>
|
||||
|
@ -711,6 +844,15 @@ white-space: nowrap;text-decoration: none;" href="/feeds/videos.xml?channel_id=<
|
|||
|
||||
<a href="/channel?id=<%=ID%>&tab=community" class="tab active" style="color:pink">Community</a>
|
||||
|
||||
|
||||
<% if (Array.isArray(playlist?.playlists)) { %>
|
||||
|
||||
<% if (playlist.playlists.length != "0") { %>
|
||||
|
||||
<a href="/channel?id=<%=ID%>&tab=playlist" class="tab" style="color:pink">Playlists</a>
|
||||
<% } %>
|
||||
<% } %>
|
||||
|
||||
<% } %>
|
||||
|
||||
<% if (tab === "shorts") { %>
|
||||
|
@ -738,6 +880,15 @@ white-space: nowrap;text-decoration: none;" href="/feeds/videos.xml?channel_id=<
|
|||
<% } %>
|
||||
<% } %>
|
||||
|
||||
|
||||
<% if (Array.isArray(playlist?.playlists)) { %>
|
||||
|
||||
<% if (playlist.playlists.length != "0") { %>
|
||||
|
||||
<a href="/channel?id=<%=ID%>&tab=playlist" class="tab" style="color:pink">Playlists</a>
|
||||
<% } %>
|
||||
<% } %>
|
||||
|
||||
<% } %>
|
||||
|
||||
<% if (tab === "live") { %>
|
||||
|
@ -765,6 +916,7 @@ white-space: nowrap;text-decoration: none;" href="/feeds/videos.xml?channel_id=<
|
|||
<% } %>
|
||||
|
||||
<% } %>
|
||||
|
||||
</div>
|
||||
|
||||
<input type="text" id="search" placeholder="Search :3" style="margin-top: 2em;height: 1em;color: #fff;background: #111;border-radius: 1em;padding: 7px;margin-left: auto;margin-right: 1em;"> </div>
|
||||
|
@ -1110,7 +1262,7 @@ width: fit-content;
|
|||
<% if (Array?.isArray( shorts.videos)) { %>
|
||||
<% shorts.videos.forEach (x => { %>
|
||||
<a href="/shorts/<%- x.videoId %>" class="shorts-video" >
|
||||
<img load="lazy" src='<%- media_proxy_url %>/proxy?url=https://vid.puffyan.us/vi/<%= x.videoId %>/hqdefault.jpg?sqp=-oaymwEbCKgBEF5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLBy_x4UUHLNDZtJtH0PXeQGoRFTgw'>
|
||||
<img load="lazy" onerror="this.src=`<%- media_proxy_url %>/proxy?url=https://vid.puffyan.us/vi/<%= x.videoId %>/hqdefault.jpg?sqp=-oaymwEbCKgBEF5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLBy_x4UUHLNDZtJtH0PXeQGoRFTgw`" src='<%- media_proxy_url %>/proxy?url=https://vid.puffyan.us/vi/<%= x.videoId %>/maxresdefault.jpg?sqp=-oaymwEbCKgBEF5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLBy_x4UUHLNDZtJtH0PXeQGoRFTgw'>
|
||||
<span class="shorts-title"><%- x.title %></span>
|
||||
</a>
|
||||
<% }) %>
|
||||
|
@ -1123,7 +1275,16 @@ width: fit-content;
|
|||
</div>
|
||||
<% } %>
|
||||
|
||||
<style>
|
||||
<!-- SHORTS-VIDEO --->
|
||||
<!-- SHORTS-VIDEO --->
|
||||
<!-- SHORTS-VIDEO --->
|
||||
<!-- SHORTS-VIDEO --->
|
||||
<!-- SHORTS-VIDEO --->
|
||||
<!-- SHORTS-VIDEO --->
|
||||
<!-- SHORTS-VIDEO --->
|
||||
<!-- SHORTS-VIDEO --->
|
||||
|
||||
<style nonce="IJD3y0awTwA2dd0pWOP+ZQ">
|
||||
.shorts-video-grid {
|
||||
max-width: 1200px;
|
||||
margin: auto;
|
||||
|
@ -1143,23 +1304,14 @@ width: fit-content;
|
|||
}
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- SHORTS-VIDEO --->
|
||||
<!-- SHORTS-VIDEO --->
|
||||
<!-- SHORTS-VIDEO --->
|
||||
<!-- SHORTS-VIDEO --->
|
||||
<!-- SHORTS-VIDEO --->
|
||||
<!-- SHORTS-VIDEO --->
|
||||
<!-- SHORTS-VIDEO --->
|
||||
<!-- SHORTS-VIDEO --->
|
||||
|
||||
<% } %>
|
||||
|
||||
|
@ -1237,6 +1389,40 @@ width: fit-content;
|
|||
|
||||
<% } %>
|
||||
|
||||
<% if (tab === "playlist") { %>
|
||||
|
||||
|
||||
|
||||
<div align="center">
|
||||
|
||||
|
||||
<div class="video-grid" >
|
||||
|
||||
|
||||
<% if (Array.isArray(playlist.playlists)) { %>
|
||||
|
||||
<% playlist.playlists.forEach (x => { %>
|
||||
<a href="/playlist?list=<%- x.playlistId %>" class="video">
|
||||
<div class="thumbnail" style="background-image: url('<%- media_proxy_url %>/proxy?url=<%- x.playlistThumbnail %>?sqp=-oaymwEbCKgBEF5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLBy_x4UUHLNDZtJtH0PXeQGoRFTgw');border-radius: 10px;"><span class="video-length"><%- x.videoCount %> Videos </span></div>
|
||||
<div class="info">
|
||||
<span class="title max-lines-2" style="font-family:PokeTube flex,sans-serif;font-weight: 1000;font-stretch: ultra-expanded;"><%- x.title %></span>
|
||||
|
||||
</div>
|
||||
</a>
|
||||
<% }) %>
|
||||
<% } %>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<% } %>
|
||||
|
||||
|
||||
<% if (tab === "community") { %>
|
||||
<% if (Array?.isArray( c?.comments)) { %>
|
||||
|
@ -1320,39 +1506,38 @@ width: fit-content;
|
|||
|
||||
|
||||
<% if (tab === "about") { %>
|
||||
<div style="text-align: left;">
|
||||
<h3 style="color:#fff;font-family:Ginto Nord,sans-serif;font-weight:900;padding: 0px;margin: 0;margin-top: 7px;margin-left: 10px;">About</h3>
|
||||
|
||||
<% if (!isMobile) { %>
|
||||
|
||||
|
||||
|
||||
<div style="display: flex;flex-direction: row;">
|
||||
|
||||
|
||||
<div style="background: #333;display: flex;flex-direction: column;margin-top: 1em;margin-left: 1em;border-radius: 1em;margin-bottom: 1em;box-sizing: border-box;width: 100%;margin-right: 20px;min-height: 19em;">
|
||||
<h3 style="color:#fff;font-family:PokeTube flex,sans-serif;font-weight:1000;font-stretch:ultra-expanded:padding: 0px;margin: 0;margin-top: 7px;margin-left: 10px;">About</h3>
|
||||
|
||||
<% if (cinv.descriptionHtml) { %>
|
||||
|
||||
<p style="color:#fff;margin-left: 10px;font-weight: bold;"><%-cinv.descriptionHtml%></p>
|
||||
<% } %>
|
||||
<% if (wiki.extract_html) { %>
|
||||
<h3 style="color:#fff;font-family:Ginto Nord,sans-serif;font-weight:900;padding: 0px;margin: 0;margin-top: 7px;margin-left: 10px;">From the web</h3>
|
||||
|
||||
<div style="color:#fff;margin-left: 10px;">
|
||||
<p style="color:#fff:font-weight: bold;">
|
||||
|
||||
<%-wiki.extract_html%> </p>
|
||||
|
||||
</div>
|
||||
|
||||
<div style="color:#fff;margin-left: 10px;">
|
||||
|
||||
<p style="margin-bottom: 10px;">
|
||||
|
||||
<a href=" <%-wiki.content_urls.desktop.page%>
|
||||
">From wikipedia </a> under CC-BY-SA 3.0
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
</p>
|
||||
<% } %>
|
||||
<div style="font-weight: bold;color:#fff;margin-left: 10px;">
|
||||
YouTube removed the about tab ;_; fix for this soon lol
|
||||
</div>
|
||||
|
||||
<% if (isMobile) { %>
|
||||
|
||||
|
||||
|
||||
|
||||
<div style="text-align: left;">
|
||||
<h3 style="color:#fff;font-family:Ginto Nord,sans-serif;font-weight:900;padding: 0px;margin: 0;margin-top: 7px;margin-left: 10px;">About</h3>
|
||||
|
||||
<% if (cinv.descriptionHtml) { %>
|
||||
|
||||
<p style="color:#fff;margin-left: 10px;font-weight: bold;"><%-cinv.descriptionHtml%></p>
|
||||
<% } %>
|
||||
<% } %>
|
||||
</div>
|
||||
<% } %>
|
||||
|
||||
|
@ -1370,7 +1555,7 @@ if (userID) {
|
|||
anchor.href = `/api/set-channel-subs?ID=${userID}&channelName=<%=j.Channel?.Metadata.Name%>&avatar=https://p.poketube.fun/<%- j.Channel?.Metadata.Avatars.Thumbnail?.$t %>&channelID=<%= ID %>`;
|
||||
} else {
|
||||
// If user ID doesn't exist in localStorage, you can handle it as needed
|
||||
console.log("User ID not found in localStorage");
|
||||
anchor.href = "/account-create"
|
||||
// Optionally, you can set a default href or display an error message.
|
||||
}
|
||||
|
||||
|
@ -1405,7 +1590,28 @@ document.getElementById('search').addEventListener('keyup', function () {
|
|||
}
|
||||
});
|
||||
});
|
||||
var isPopupOpen = false;
|
||||
|
||||
function togglePopup() {
|
||||
if (isPopupOpen) {
|
||||
closePopup();
|
||||
} else {
|
||||
document.getElementById('popup-container').style.display = 'block';
|
||||
document.body.style.overflow = 'hidden';
|
||||
}
|
||||
isPopupOpen = !isPopupOpen;
|
||||
}
|
||||
|
||||
function closePopup() {
|
||||
document.getElementById('popup-container').style.display = 'none';
|
||||
document.body.style.overflow = 'auto';
|
||||
isPopupOpen = false;
|
||||
}
|
||||
|
||||
document.getElementById('popup-trigger').addEventListener('click', function (event) {
|
||||
event.preventDefault();
|
||||
togglePopup();
|
||||
});
|
||||
// @license-end
|
||||
|
||||
</script>
|
||||
|
@ -1417,8 +1623,4 @@ document.getElementById('search').addEventListener('keyup', function () {
|
|||
|
||||
<% } catch (error) { %>
|
||||
<% } %>
|
||||
<script>
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.register('service-worker.js');
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
<!--
|
||||
This Source Code Form is subject to the terms of the GNU General Public License:
|
||||
|
||||
Copyright (C) 2021-2023 POKETUBE (https://codeberg.org/Ashley/poketube)
|
||||
Copyright (C) 2021-2024 POKETUBE (https://codeberg.org/Ashley/poketube)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -31,13 +31,12 @@
|
|||
<meta content=@PoketaleBot name=twitter:site>
|
||||
<meta content=@PoketaleBot name=twitter:creator>
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
|
||||
<meta name="darkreader-lock"> <!-- tells dark reader that the site has a dark theme and to turn itself off -->
|
||||
<link href=/css/app-cdn.min.css rel=stylesheet>
|
||||
<link href=/css/app-cdn.min.css rel=stylesheet>
|
||||
<link href=/css/app.main.css?v=45 rel=stylesheet>
|
||||
<link href=/css/search.main.css rel=stylesheet>
|
||||
<link href=/css/watch.main.css rel=stylesheet>
|
||||
<link href="https://fonts.poketube.fun/css/fonts.css" rel=stylesheet>
|
||||
<meta content="#1a1a1a" name="theme-color">
|
||||
</head>
|
||||
<style>
|
||||
|
@ -519,6 +518,10 @@ Discover Popular videos on poketube!
|
|||
<script>
|
||||
// @license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-3.0-or-later
|
||||
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.register('service-worker.js');
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
let bgs = document.querySelectorAll('[data-bg]');
|
||||
let bgCount = bgs.length;
|
||||
|
@ -1319,8 +1322,24 @@ links.forEach(link => {
|
|||
}</style>
|
||||
<% } %>
|
||||
|
||||
<script> // @license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-3.0-or-later
|
||||
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.getRegistrations().then(function(registrations) {
|
||||
for (let registration of registrations) {
|
||||
registration.unregister();
|
||||
}
|
||||
});
|
||||
if ('caches' in window) {
|
||||
caches.keys().then(function(cacheNames) {
|
||||
cacheNames.forEach(function(cacheName) {
|
||||
caches.delete(cacheName);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
</body >
|
||||
|
||||
</html> <% } %>
|
||||
|
|
1111
html/gamehub.ejs
Normal file
1111
html/gamehub.ejs
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
|
@ -3,7 +3,7 @@
|
|||
|
||||
This Source Code Form is subject to the terms of the GNU General Public License:
|
||||
|
||||
Copyright (C) 2021-2023 POKETUBE (https://codeberg.org/Ashley/poketube)
|
||||
Copyright (C) 2021-2024 POKETUBE (https://codeberg.org/Ashley/poketube)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -557,32 +557,68 @@ background: none !important;
|
|||
</div>
|
||||
|
||||
<% if (!f) { %>
|
||||
<% k.Video.Recommendations.Video.forEach(x => { %>
|
||||
<div class="video" >
|
||||
<% if (!optout) { %>
|
||||
|
||||
<a href="/lite?v=<%= x.id %>" class="thumbnail" style="background-image: url('/vi/<%= x.id %>/hqdefault.jpg?sqp=-oaymwEbCKgBEF5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLBy_x4UUHLNDZtJtH0PXeQGoRFTgw');border-radius: 9.5px;" > <span class="video-length"><%=x.duration || "LIVE" %></span>
|
||||
<% } %>
|
||||
<% if (optout) { %>
|
||||
<% if (inv_vid.recommendedVideos) { %>
|
||||
|
||||
<a href="/lite?v=<%= x.id %>&t=f" class="thumbnail" style="background-image: url('/vi/<%= x.id %>/hqdefault.jpg?sqp=-oaymwEbCKgBEF5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLBy_x4UUHLNDZtJtH0PXeQGoRFTgw');border-radius: 9.5px;" > <span class="video-length"><%- x.duration || "LIVE"%></span>
|
||||
<% } %>
|
||||
</a>
|
||||
<% inv_vid?.recommendedVideos.forEach(x => { %>
|
||||
<div class="fade-in video">
|
||||
<% if (!optout) { %><a class="thumbnail" href="/lite?v=<%= x.videoId %>" style="background-image:url(<%- media_proxy_url %>/proxy?url=https://vid.puffyan.us/vi/<%= x.videoId %>/hqdefault.jpg?sqp=-oaymwEbCKgBEF5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLBy_x4UUHLNDZtJtH0PXeQGoRFTgw);border-radius:9.5px" alt="<%= x.Title %>"><span class="video-length"><%- turntomins(x.lengthSeconds) || "LIVE"%></span><% } %><% if (optout) { %><a class="thumbnail"href="/lite?v=<%= x.videoId %>&m=f"style="background-image:url(<%- media_proxy_url %>/proxy?url=https://vid.puffyan.us/vi/<%= x.videoId %>/hqdefault.jpg?sqp=-oaymwEbCKgBEF5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLBy_x4UUHLNDZtJtH0PXeQGoRFTgw);border-radius:9.5px"alt="<%= x.Title %>"><span class="video-length"><%- x.duration || "LIVE"%></span><% } %></a>
|
||||
<div class="info">
|
||||
|
||||
<% if (!optout) { %>
|
||||
<a href="/lite?v=<%= x.id %>" class="title max-lines-2" title="<%= x.Title %>" style="font-stretch: 100%;font-weight: 800;"><%= x.Title %></a>
|
||||
<a class="max-lines-2 title" href="/lite?v=<%= x.videoId %>" style="font-stretch:ultra-expanded;font-weight:850" title="<%= x.Title %>">
|
||||
<%= x.title %>
|
||||
</a>
|
||||
<% } %>
|
||||
<% if (optout) { %>
|
||||
<a href="/lite?v=<%= x.id %>&t=f" class="title max-lines-2" title="<%= x.Title %>" style="font-stretch: 100%;font-weight: 800;"><%= x.Title %></a>
|
||||
<a class="max-lines-2 title" href="/lite?v=<%= x.videoId %>&m=f" style="font-stretch:100%;font-weight:800" title="<%= x.Title %>">
|
||||
<%= x.title %>
|
||||
</a>
|
||||
<% } %>
|
||||
<div>
|
||||
<a class="max-lines-2" href="/channel?id=<%= x.Channel.id %>" style="-webkit-line-clamp: 1;width: 12em;word-wrap: break-word;"><%=x.Channel.Name %></a>
|
||||
<div class="video-views"> <%= x.uploadedAt.replace("Streamed", "Live") %> • <%= convert(x.views) %> views </div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a class="max-lines-2" href="/channel?id=<%= x.authorId %>@youtube.com" style="-webkit-line-clamp:1;width:12em;word-wrap:break-word">
|
||||
<%=x.author %>
|
||||
</a>
|
||||
<div class="video-views">
|
||||
|
||||
<%= convert(x.viewCount) %> views
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% }) %>
|
||||
|
||||
|
||||
<% } %>
|
||||
<% } %>
|
||||
|
||||
<% if (inv_vid.recommendedVideos.length < 1) { %>
|
||||
<% channel_uploads.latestVideos.forEach(x => { %>
|
||||
<div class="fade-in video">
|
||||
<% if (!optout) { %><a class="thumbnail" href="/lite?v=<%= x.videoId %>" style="background-image:url(<%- media_proxy_url %>/proxy?url=https://vid.puffyan.us/vi/<%= x.videoId %>/hqdefault.jpg?sqp=-oaymwEbCKgBEF5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLBy_x4UUHLNDZtJtH0PXeQGoRFTgw);border-radius:9.5px" alt="<%= x.Title %>"><span class="video-length"><%- turntomins(x.lengthSeconds) || "LIVE"%></span><% } %><% if (optout) { %><a class="thumbnail"href="/lite?v=<%= x.videoId %>&m=f"style="background-image:url(<%- media_proxy_url %>/proxy?url=https://vid.puffyan.us/vi/<%= x.videoId %>/hqdefault.jpg?sqp=-oaymwEbCKgBEF5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLBy_x4UUHLNDZtJtH0PXeQGoRFTgw);border-radius:9.5px"alt="<%= x.Title %>"><span class="video-length"><%- x.duration || "LIVE"%></span><% } %></a>
|
||||
<div class="info">
|
||||
<% if (!optout) { %>
|
||||
<a class="max-lines-2 title" href="/lite?v=<%= x.videoId %>" style="font-stretch:ultra-expanded;font-weight:850" title="<%= x.Title %>">
|
||||
<%= x.title %>
|
||||
</a>
|
||||
<% } %>
|
||||
<% if (optout) { %>
|
||||
<a class="max-lines-2 title" href="/lite?v=<%= x.videoId %>&m=f" style="font-stretch:100%;font-weight:800" title="<%= x.Title %>">
|
||||
<%= x.title %>
|
||||
</a>
|
||||
<% } %>
|
||||
<div>
|
||||
<a class="max-lines-2" href="/channel?id=<%= x.authorId %>@youtube.com" style="-webkit-line-clamp:1;width:12em;word-wrap:break-word">
|
||||
<%=x.author %>
|
||||
</a>
|
||||
<div class="video-views">
|
||||
|
||||
<%= convert(x.viewCount) %> views
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% }) %>
|
||||
<% } %>
|
||||
|
||||
|
|
265
html/playlist.ejs
Normal file
265
html/playlist.ejs
Normal file
|
@ -0,0 +1,265 @@
|
|||
<!--
|
||||
This Source Code Form is subject to the terms of the GNU General Public License:
|
||||
|
||||
Copyright (C) 2021-2024 POKETUBE (https://codeberg.org/Ashley/poketube)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
--><!DOCTYPE html><html style="background:#000000">
|
||||
<head>
|
||||
<title>Poke | <%- p.title %> </title>
|
||||
<link href=/css/yt-ukraine.svg?v=6 rel=icon>
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
<meta content=website property=og:type>
|
||||
<meta name="viewport" content="width=device-1200px, initial-scale=1.0, shrink-to-fit=yes, viewport-fit=cover">
|
||||
<meta content="Poke - <%- p.title %> " property=og:title>
|
||||
<meta content="<%- p.description %>" property=twitter:description>
|
||||
<meta content="<%- mediaproxy %>/proxy?url=<%- p.playlistThumbnail %>" property="og:image" />
|
||||
<meta content=summary_large_image name=twitter:card>
|
||||
<link href=/css/app-cdn.min.css rel=stylesheet>
|
||||
<link href=/css/app.main.css?v=8 rel=stylesheet>
|
||||
<link href="/css/watch.main.css?v=56" rel=stylesheet>
|
||||
<link href=https://p.poketube.fun/https://site-assets.fontawesome.com/releases/v6.1.1/css/all.css rel=stylesheet>
|
||||
<style>
|
||||
a.class:hover {
|
||||
font-weight:bold
|
||||
}
|
||||
summary{
|
||||
color:gray;
|
||||
}
|
||||
summary:hove
|
||||
color:white;
|
||||
}
|
||||
|
||||
</style>
|
||||
<!-- WIGGLE WIGGLE WIGGLE -->
|
||||
<style>
|
||||
body{
|
||||
overflow-x: hidden; /* Hide horizontal scrollbar */
|
||||
color:#111111;
|
||||
}
|
||||
|
||||
.animated {
|
||||
-webkit-animation-duration: 10s;
|
||||
animation-duration: 10s;
|
||||
-webkit-animation-fill-mode: both;
|
||||
animation-fill-mode: both;
|
||||
animation-iteration-count: infinite;
|
||||
-moz-animation-iteration-count: infinite;
|
||||
-webkit-animation-iteration-count: infinite;
|
||||
-o-animation-iteration-count: infinite;
|
||||
}
|
||||
|
||||
@-webkit-keyframes wiggle {
|
||||
0% { -webkit-transform: skewX(9deg); }
|
||||
10% { -webkit-transform: skewX(-8deg); }
|
||||
20% { -webkit-transform: skewX(7deg); }
|
||||
30% { -webkit-transform: skewX(-6deg); }
|
||||
40% { -webkit-transform: skewX(5deg); }
|
||||
50% { -webkit-transform: skewX(-4deg); }
|
||||
60% { -webkit-transform: skewX(3deg); }
|
||||
70% { -webkit-transform: skewX(-2deg); }
|
||||
80% { -webkit-transform: skewX(1deg); }
|
||||
90% { -webkit-transform: skewX(0deg); }
|
||||
100% { -webkit-transform: skewX(0deg); }
|
||||
}
|
||||
|
||||
@keyframes wiggle {
|
||||
0% { transform: skewX(9deg); }
|
||||
10% { transform: skewX(-8deg); }
|
||||
20% { transform: skewX(7deg); }
|
||||
30% { transform: skewX(-6deg); }
|
||||
40% { transform: skewX(5deg); }
|
||||
50% { transform: skewX(-4deg); }
|
||||
60% { transform: skewX(3deg); }
|
||||
70% { transform: skewX(-2deg); }
|
||||
80% { transform: skewX(1deg); }
|
||||
90% { transform: skewX(0deg); }
|
||||
100% { transform: skewX(0deg); }
|
||||
}
|
||||
|
||||
.wiggle {
|
||||
-webkit-animation-name: wiggle;
|
||||
animation-name: wiggle;
|
||||
-webkit-animation-timing-function: ease-in;
|
||||
animation-timing-function: ease-in;
|
||||
}
|
||||
|
||||
.animated.wiggle {
|
||||
-webkit-animation-duration: 0.75s;
|
||||
animation-duration: 0.75s;
|
||||
}
|
||||
|
||||
:root {
|
||||
--text-primary: #fff;
|
||||
--text-secondary: #fff;
|
||||
--text-link: #3ea6ff;
|
||||
|
||||
--app-background: #111111;
|
||||
--context-menu-background: #333;
|
||||
--border-color: #444;
|
||||
--item-hover-background: #373737;
|
||||
--item-active-background: #383838;
|
||||
|
||||
--top-bar-background: #202020;
|
||||
--guide-background: #212121;
|
||||
|
||||
--thumbnail-background: #252525;
|
||||
|
||||
--channel-info-background: #181818;
|
||||
--channel-contents-background: #0f0f0f;
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: 20px;
|
||||
background-color: #f44336;
|
||||
color: white;
|
||||
opacity: 1;
|
||||
transition: opacity 0.6s;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.alert.success {background-color: #04AA6D;}
|
||||
.alert.info {background-color: #2196F3;}
|
||||
.alert.warning {background-color: #ff9800;}
|
||||
|
||||
.closebtn {
|
||||
margin-left: 15px;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
float: right;
|
||||
font-size: 22px;
|
||||
line-height: 20px;
|
||||
cursor: pointer;
|
||||
transition: 0.3s;
|
||||
}
|
||||
a{
|
||||
border-radius:13px
|
||||
}
|
||||
|
||||
.video-list > p {
|
||||
font-family:Ubuntu
|
||||
}
|
||||
.closebtn:hover {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.playlist-video > .info > .title {
|
||||
border-radius:0em;
|
||||
max-height: 1.9em;
|
||||
}
|
||||
|
||||
.playlist-info>.title {
|
||||
font-family: "PokeTube flex";
|
||||
font-stretch: ultra-expanded;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.playlist-info{
|
||||
position: sticky
|
||||
}
|
||||
|
||||
.playlist-info::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 13em;
|
||||
height: 447px;
|
||||
background-size: cover;
|
||||
filter: blur(53px);
|
||||
backdrop-filter: blur(157px);
|
||||
z-index: -1;
|
||||
background-image: url(<%- mediaproxy %>/proxy?url=<%- p.playlistThumbnail %>?sqp=-oaymwEWCKgBEF5IWvKriqkDCQgBFQAAiEIYAQ==&rs=AOn4CLA9kTQiXKs92q5RXRPYMkL6jKhNJQsqp=-oaymwEXCNACELwBSFryq4qpAwkIARUAAIhCGAE=&rs=AOn4CLCLG7gzsIdtlp7ugZJH8YaAHX5bIw&days_since_epoch=19755);
|
||||
margin-left: 82px;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<nav>
|
||||
<div class="left"><a class="class" href="/143" style=font-family:Inter,sans-serif;color:#fff> <img style="transform: scale(1.3);padding-left:0.9em;width: 8.5em;display: block;margin-left: auto;margin-right: auto;" src="/css/logo.svg?v=5"> </a> </div>
|
||||
<div class="middle">
|
||||
<div class="search">
|
||||
|
||||
<form action="/search">
|
||||
<input class="search-bar" autocomplete="on" id="fname" name="query" placeholder="" style="color:#fff;font-family:Inter,sans-serif;border-radius: 8px;" data-ddg-inputtype="identities.firstName">
|
||||
|
||||
|
||||
<button class="btn btn-success" type="submit"><i class="fa-light fa-search"></i></button>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="right">
|
||||
<a href="/privacy" style="text-decoration: none;" title="Privacy Policy">
|
||||
<i style="display: block;margin-left: auto;margin-right: auto;" class="fa-light fa-shield"></i>
|
||||
</a>
|
||||
|
||||
|
||||
</div>
|
||||
</nav>
|
||||
<div class="playlist-page" style="margin-left: auto;margin-right: auto;width: 56em;">
|
||||
<div class="playlist-info" style="max-height: 26em;border-radius: 1em;">
|
||||
<% if (!p.mixId) { %>
|
||||
|
||||
<div class="thumbnail" style="background-image: url('<%- mediaproxy %>/proxy?url=<%- p.playlistThumbnail %>sqp=-oaymwEXCNACELwBSFryq4qpAwkIARUAAIhCGAE=&rs=AOn4CLCLG7gzsIdtlp7ugZJH8YaAHX5bIw&days_since_epoch=19755');border-radius: 13px;border: 1px solid #ff0064">
|
||||
</div> <% } %>
|
||||
|
||||
<p class="title"><%- p.title %> </p>
|
||||
<% if (!p.mixId) { %>
|
||||
<span class="info"><%- p.videoCount %> videos • <%- p?.viewCount?.toLocaleString() %> views • by <%- p.author %> </span>
|
||||
<% } %>
|
||||
|
||||
<span class="description"><%- p.description %></span>
|
||||
<div class="channel-info">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="video-list playlist-video-list">
|
||||
<% p.videos.forEach(x => { %>
|
||||
|
||||
<div class="playlist-video">
|
||||
<a href="/watch?v=<%- x.videoId %>" class="index">
|
||||
<%- x.index + 1 %>
|
||||
</a>
|
||||
<a href="/watch?v=<%- x.videoId %>" class="thumbnail"
|
||||
style="background-image: url('<%- mediaproxy %>/proxy?url=https://vid.puffyan.us/vi/<%- x.videoId %>/hqdefault.jpg?sqp=-oaymwEjCNACELwBSFryq4qpAxUIARUAAAAAGAElAADIQj0AgKJDeAE=&rs=AOn4CLBibY6d4Dg0K69NC-0b7NFsD7AH1w');">
|
||||
</a>
|
||||
<div class="info">
|
||||
<a href="/watch?v=<%- x.videoId %>" class="title max-lines-2">
|
||||
<%- x.title %>
|
||||
</a>
|
||||
<div>
|
||||
<a href="/channel?id=<%- x.authorId %>" style="border-radius:0em"><%- x.author %></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<% }) %>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/css/custom-css.js"> </script>
|
||||
|
||||
</body>
|
||||
</html>
|
File diff suppressed because it is too large
Load diff
78
html/rewind.ejs
Normal file
78
html/rewind.ejs
Normal file
|
@ -0,0 +1,78 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Poke Rewind</title>
|
||||
<link href="/css/yt-ukraine.svg?v=6" rel=icon>
|
||||
<meta content="website" property="og:type">
|
||||
<meta content="Poke Rewind 2023! - see the year 2023 in poke1" property="twitter:description">
|
||||
<meta content="Poke Rewind!" property="og:title">
|
||||
<meta content="https://cdn.glitch.global/d68d17bb-f2c0-4bc3-993f-50902734f652/aa70111e-5bcd-4379-8b23-332a33012b78.image.png?v=1701898829884" property="og:image" />
|
||||
<meta content="summary_large_image" name="twitter:card">
|
||||
<style>
|
||||
body {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
font-family: 'Arial', sans-serif;
|
||||
background-color: #1a1a1a;
|
||||
color: #ffffff;
|
||||
}
|
||||
img {
|
||||
height: 2em;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
#countdown {
|
||||
font-size: 36px;
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
border: 2px solid #444;
|
||||
border-radius: 10px;
|
||||
background-color: #333;
|
||||
box-shadow: 0 0 10px rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div>
|
||||
|
||||
<img src="/css/logo-poke.svg">
|
||||
<div id="countdown"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// @license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-3.0-or-later
|
||||
|
||||
const countDownDate = new Date("December 28, 2023 00:00:00 UTC").getTime();
|
||||
|
||||
const x = setInterval(function() {
|
||||
const now = new Date().getTime();
|
||||
|
||||
const distance = countDownDate - now;
|
||||
|
||||
const days = Math.floor(distance / (1000 * 60 * 60 * 24));
|
||||
const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
||||
const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
|
||||
const seconds = Math.floor((distance % (1000 * 60)) / 1000);
|
||||
|
||||
document.getElementById("countdown").innerHTML = `${days}d ${hours}h ${minutes}m ${seconds}s`;
|
||||
|
||||
// If the countdown is over, display a message
|
||||
if (distance < 0) {
|
||||
clearInterval(x);
|
||||
document.getElementById("countdown").innerHTML = "poke~ Rewind";
|
||||
}
|
||||
}, 1000); // Update every 1000 milliseconds
|
||||
// @license-end
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -216,14 +216,21 @@
|
|||
</div>
|
||||
<div class="search-wrap--home">
|
||||
<form name="x" id="search_form_homepage" class="search" action="/web" method="get">
|
||||
|
||||
<input placeholder="Search the web" name="query" autocomplete="off" id="search_form_input_homepage" class="search__input" type="text" autofocus />
|
||||
|
||||
<div>
|
||||
<button class="btn btn-success" type="submit" style="margin-top: 1em;margin-left: auto;text-align: center;display: flex;flex-direction: column;background: #fff;background-color: #303134;border: 1px solid #303134;border-radius: 4px;color: #e8eaed;font-family: arial,sans-serif;font-size: 14px;padding: 0 16px;line-height: 27px;height: 36px;min-width: 54px;margin-right: 13em;text-align: center;cursor: pointer;user-select: none;">
|
||||
<p style="margin-top: auto;margin-bottom: auto;font-weight: 1000;margin-left: 6px;font-stretch: ultra-expanded;font-family:"poketube flex";Poketube flex;">Search Poke</p>
|
||||
</button>
|
||||
|
||||
<button class="btn btn-success" type="submit" style="margin-top: 1em;margin-left: auto;margin-right: 8em;align-self: center;text-align: center;display: flex;flex-direction: column;height: 5em;background: #fff;color: #000;border: none;width: 8em;"><p style="margin-top: auto;margin-bottom: auto;font-weight: 1000;margin-left: 6px;font-stretch: ultra-expanded;font-family:"poketube flex";Poketube flex;">Search Poke</p></button>
|
||||
<button class="btn btn-success" name="lucky" value="true" type="submit" style="margin-top: 1em;margin-left: auto;text-align: center;display: flex;flex-direction: column;background: #fff;background-color: #303134;border: 1px solid #303134;border-radius: 4px;color: #e8eaed;font-family: arial,sans-serif;font-size: 14px;padding: 0 16px;line-height: 27px;height: 36px;min-width: 54px;margin-right: 9em;text-align: center;cursor: pointer;user-select: none;margin-top: -38px;margin-left: 21em;">
|
||||
<p style="margin-top: auto;margin-bottom: auto;font-weight: 1000;margin-left: 6px;font-stretch: ultra-expanded;font-family:"poketube flex";Poketube flex;">Im feeling lucky</p>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="downnav">
|
||||
<span style="color:#fff;" id="weatherInfo"></span> - <a style="color:#fff" href="/map"> PokeMaps </a> - <a style="color:#fff" href="/account-create">My Account</a> - <a style="color:#fff" href="/privacy">Privacy</a> - <a style="color:#fff" href="https://codeberg.org/ashley/poketube">Git</a>
|
||||
<span style="color:#fff;" id="weatherInfo"></span> - <a style="color:#fff" href="/translate"> Translate </a> - <a style="color:#fff" href="/map"> PokeMaps </a> - <a style="color:#fff" href="/account-create">My Account</a> - <a style="color:#fff" href="/privacy">Privacy</a> - <a style="color:#fff" href="https://codeberg.org/ashley/poketube">Git</a>
|
||||
<div style="float: right;">
|
||||
<a style="color:#fff" id="osInfo"></a> <a style="color:#fff;margin-right: 1em;" href="/license">License</a>
|
||||
</div>
|
||||
|
@ -231,7 +238,6 @@
|
|||
|
||||
|
||||
|
||||
</form>
|
||||
<script>
|
||||
const userAgent = navigator.userAgent.toLowerCase();
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<!--
|
||||
This Source Code Form is subject to the terms of the GNU General Public License:
|
||||
|
||||
Copyright (C) 2021-2023 POKETUBE (https://codeberg.org/Ashley/poketube)
|
||||
Copyright (C) 2021-2024 POKETUBE (https://codeberg.org/Ashley/poketube)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -134,7 +134,19 @@ summary:hover{
|
|||
font-family: ubuntu, sans-serif;
|
||||
}
|
||||
|
||||
|
||||
.search-result{
|
||||
color: white;
|
||||
width: 52em;
|
||||
display: block;
|
||||
white-space: -moz-pre-wrap !important;
|
||||
white-space: -pre-wrap;
|
||||
white-space: -o-pre-wrap;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
white-space: -webkit-pre-wrap;
|
||||
word-break: break-all;
|
||||
white-space: normal;
|
||||
}
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
|
@ -445,17 +457,17 @@ Web
|
|||
<div class="video-list" >
|
||||
|
||||
<% results.forEach(x => { %>
|
||||
<div class="video" style="height: 6em;">
|
||||
<div class="video" style="height: 7em;">
|
||||
|
||||
<a style="min-width: 81em;" href="<%= x.link %>"><%= x.title %></a><br>
|
||||
<p style="color:gray;display: flex;flex-direction: column;width: 48em;margin-top: -8em;"><%= x.link %><br>
|
||||
<a style="min-width: 81em;" href="<%= x.url %>"><%= x.title %></a><br>
|
||||
<p style="color:gray;display: flex;flex-direction: column;width: 48em;margin-top: -8em;"><%= x.url %><br>
|
||||
<% if (!isMobile) { %>
|
||||
|
||||
<span style="color:white;width: 48em;display: flex;"><%= x.snippet %></span>
|
||||
<span class="search-result"><%- x.description %></span>
|
||||
<% } %>
|
||||
<% if (isMobile) { %>
|
||||
|
||||
<span style="color:white;max-width: 15em;display: flex;"><%= x.snippet %></span>
|
||||
<span class="search-result"><%- x.description %></span>
|
||||
<% } %>
|
||||
</p>
|
||||
</div>
|
||||
|
@ -465,12 +477,22 @@ Web
|
|||
</a>
|
||||
</div>
|
||||
|
||||
<script src="/css/custom-css.js"> </script>
|
||||
|
||||
<script src="/css/custom-css.js"> </script>
|
||||
<script> if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.getRegistrations().then(function(registrations) {
|
||||
for (let registration of registrations) {
|
||||
registration.unregister();
|
||||
}
|
||||
});
|
||||
if ('caches' in window) {
|
||||
caches.keys().then(function(cacheNames) {
|
||||
cacheNames.forEach(function(cacheName) {
|
||||
caches.delete(cacheName);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}</script>
|
||||
</body>
|
||||
|
||||
<script>
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.register('service-worker.js');
|
||||
}
|
||||
</script>
|
140
html/search.ejs
140
html/search.ejs
|
@ -1,7 +1,7 @@
|
|||
<!--
|
||||
This Source Code Form is subject to the terms of the GNU General Public License:
|
||||
|
||||
Copyright (C) 2021-2023 POKETUBE (https://codeberg.org/Ashley/poketube)
|
||||
Copyright (C) 2021-2024 POKETUBE (https://codeberg.org/Ashley/poketube)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -23,10 +23,10 @@
|
|||
<link rel="manifest" href="/manifest.json">
|
||||
<link href=/css/yt-ukraine.svg?v=6 rel=icon>
|
||||
<link href=/css/app-cdn.min.css rel=stylesheet>
|
||||
<link href=/css/app.main.css?v=25 rel=stylesheet>
|
||||
<link href=/css/app.main.css?v=333 rel=stylesheet>
|
||||
<link href=/css/search.main.css rel=stylesheet>
|
||||
<link href=/css/watch.main.css rel=stylesheet>
|
||||
<link rel="search" type="application/opensearchdescription+xml" title="PokeTube" href="https://poketube.fun/api/opensearch" />
|
||||
<meta name="darkreader-lock"> <!-- tells dark reader that the site has a dark theme and to turn itself off -->
|
||||
<meta content="Searching <%=q%> - Poke" property=og:title>
|
||||
<% if (q == "do the harlem shake") { %>
|
||||
<meta content="DO THE HARLEM SHAKE" property=twitter:description>
|
||||
|
@ -100,7 +100,19 @@ summary:hover{
|
|||
font-family: ubuntu, sans-serif;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background-color: #333;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 5px;
|
||||
text-align:center;
|
||||
}
|
||||
.container > * {
|
||||
text-align:center !important;
|
||||
|
||||
}
|
||||
.info > div {
|
||||
font-family:Ubuntu, sans-serif;
|
||||
}
|
||||
|
@ -276,6 +288,16 @@ border:solid;
|
|||
transform: scale(1, 1);
|
||||
}
|
||||
|
||||
.something-background-a {
|
||||
background-image: url('<%- media_proxy_url %>/proxy?url=https://static.wikia.nocookie.net/omori/images/f/fc/Something_Bed_(2018_Demo).gif') !important;
|
||||
}
|
||||
.something-background-b {
|
||||
background-image: url('<%- media_proxy_url %>/proxy?url=https://static.wikia.nocookie.net/omori/images/1/14/Hangman_%28Laptop%29.png') !important;
|
||||
}
|
||||
.something-background-c {
|
||||
background-image: url('<%- media_proxy_url %>/proxy?url=https://static.wikia.nocookie.net/omori/images/6/67/Nanci_Before.png') !important;
|
||||
}
|
||||
|
||||
.loading .spinner {
|
||||
display: inline-block;
|
||||
border: 5px solid rgba(255, 255, 255, 0.2);
|
||||
|
@ -332,11 +354,22 @@ video[counter].classList.add("shake");
|
|||
</script>
|
||||
<% } %>
|
||||
|
||||
<% if (q != "do the harlem shake") { %>
|
||||
<% if (q == "do a barrel roll") { %>
|
||||
<style>
|
||||
@keyframes barrelRoll {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
<% if (q != "want you gone") { %> <% if (q != "portal 2 ending") { %> <% if (q != "credits") { %> <% if (q != "glados") { %>
|
||||
body {
|
||||
animation: barrelRoll 2s alternate; /* Adjust the duration as needed */
|
||||
}
|
||||
</style>
|
||||
|
||||
<% if (q != "something") { %>
|
||||
<% } %>
|
||||
|
||||
<% if (q != "do the harlem shake") { %> <% if (q != "want you gone") { %> <% if (q != "portal 2 ending") { %> <% if (q != "credits") { %> <% if (q != "glados") { %> <% if (q != "something") { %>
|
||||
|
||||
<a class="class" href="/143" style=font-family:Inter,sans-serif;color:#fff> <img style="transform: scale(1.3);width:8.5em;display: block;margin-left: auto;margin-right: auto;" src="/css/logo.svg?v=5"></a>
|
||||
|
||||
|
@ -344,8 +377,8 @@ video[counter].classList.add("shake");
|
|||
|
||||
|
||||
<% } %>
|
||||
<% } %>
|
||||
<% } %>
|
||||
<% } %><% } %>
|
||||
|
||||
|
||||
<% } %>
|
||||
<% } %>
|
||||
|
@ -376,7 +409,6 @@ video[counter].classList.add("shake");
|
|||
<button class="btn btn-success" type=submit><i class="fa-light fa-search"></i></button>
|
||||
|
||||
</form>
|
||||
<img src="https://search-metrics.poketube.fun/t/rep.gif" style="border:0;width: 0;visibility: hidden;">
|
||||
|
||||
</div> </div>
|
||||
|
||||
|
@ -468,6 +500,23 @@ Web </a>
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<% if (q.includes("suicide")) { %>
|
||||
|
||||
<div class="container">
|
||||
<h2 style="font-family: 'PokeTube Flex';font-size: large;text-align: left;font-stretch: ultra-expanded;
|
||||
font-weight: 1000;">You are not alone</h2>
|
||||
<p>
|
||||
if you or somebody you know is having a bad time, talk to somebody today.
|
||||
</p>
|
||||
<p>
|
||||
if you are from the US, call 988. if you arent <a href="https://www.psychologytoday.com/us/basics/suicide/suicide-prevention-hotlines-resources-worldwide"> see this url.</a>
|
||||
<br> <br> dont worry, ur not alone <3 and you are really important btw!
|
||||
</p>
|
||||
|
||||
</div>
|
||||
<% } %>
|
||||
|
||||
|
||||
<% if (!tab) { %>
|
||||
|
||||
<% invresults.forEach (x => { %>
|
||||
|
@ -509,7 +558,7 @@ font-weight: 1000;
|
|||
|
||||
<div style="border-top: 1px solid var(--border-color);width: 100%;display: flex;gap: 43em;padding: 0;margin: 0;">
|
||||
|
||||
<% if (continuation !== "1") { %>
|
||||
<% if (Number(continuation) >= "2") { %>
|
||||
|
||||
<p style="text-align: left;margin-left: 16em;color: var(--text-secondary);text-decoration: none;">
|
||||
<a href="/search?query=<%=q%>">First Page</a> </p>
|
||||
|
@ -518,7 +567,7 @@ font-weight: 1000;
|
|||
</p>
|
||||
|
||||
<% } %>
|
||||
<% if (continuation == "1" || !continuation) { %>
|
||||
<% if (Number(continuation) <= "0" || !continuation) { %>
|
||||
<p style="text-align: left;margin-left: 16em;;color: var(--text-secondary);text-decoration: none;">
|
||||
<a href="/search?query=<%=q%>&continuation=2<% if (date) { %>&date=<%= date %><% } %><% if (duration) { %>&duration=<%= duration %><% } %><% if (sort) { %>&sort=<%= sort %><% } %>
|
||||
">Next Page</a>
|
||||
|
@ -575,11 +624,70 @@ font-weight: 1000;
|
|||
</div>
|
||||
|
||||
<script src="/css/custom-css.js"> </script>
|
||||
<script>
|
||||
// @license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-3.0-or-later
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.getRegistrations().then(function(registrations) {
|
||||
for (let registration of registrations) {
|
||||
registration.unregister();
|
||||
}
|
||||
});
|
||||
if ('caches' in window) {
|
||||
caches.keys().then(function(cacheNames) {
|
||||
cacheNames.forEach(function(cacheName) {
|
||||
caches.delete(cacheName);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
if (localStorage.getItem('liar.')) {
|
||||
var thumbnails = document.querySelectorAll('.thumbnail');
|
||||
|
||||
function changeFavicon(newFaviconUrl) {
|
||||
var oldFavicon = document.querySelector('link[rel="icon"]');
|
||||
if (oldFavicon) {
|
||||
oldFavicon.remove();
|
||||
}
|
||||
var link = document.createElement('link');
|
||||
link.rel = 'icon';
|
||||
link.href = newFaviconUrl;
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
changeFavicon("<%- media_proxy_url %>/proxy?url=https://static.wikia.nocookie.net/omori/images/d/d8/Something_Float_%282018_Demo%29.gif")
|
||||
var textList = [
|
||||
"sunny... i love you",
|
||||
"SUNNY... I'm... sorry..."
|
||||
];
|
||||
|
||||
// Select four different text elements
|
||||
var textElements = document.querySelectorAll('.title');
|
||||
|
||||
textElements.forEach(function(element, index) {
|
||||
element.textContent = textList[index % textList.length]; // Use modulo to cycle through textList
|
||||
});
|
||||
|
||||
|
||||
var backgroundClasses = ['something-background-a', 'something-background-b', 'something-background-c'];
|
||||
|
||||
// Loop through each thumbnail element and assign a random background image class
|
||||
thumbnails.forEach(function(thumbnail) {
|
||||
var randomIndex = Math.floor(Math.random() * backgroundClasses.length);
|
||||
thumbnail.classList.add(backgroundClasses[randomIndex]);
|
||||
});
|
||||
|
||||
document.title = "sunny..im..sorry"
|
||||
var audio = new Audio('https://p.poketube.fun/https://cdn.glitch.global/d68d17bb-f2c0-4bc3-993f-50902734f652/Lost_at_Sea.ogg?v=1706879048533');
|
||||
audio.loop = true;
|
||||
audio.autoplay = true;
|
||||
}
|
||||
});
|
||||
|
||||
// @license-end
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
<script>
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.register('service-worker.js');
|
||||
}
|
||||
</script>
|
||||
|
431
html/translate.ejs
Normal file
431
html/translate.ejs
Normal file
|
@ -0,0 +1,431 @@
|
|||
<!--
|
||||
This Source Code Form is subject to the terms of the GNU General Public License:
|
||||
|
||||
Copyright (C) 2021-2024 PokeTube (https://codeberg.org/Ashley/poketube)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
-->
|
||||
<!doctype html>
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>PokeTranslate</title>
|
||||
<link rel="icon" href="/static/yt-ukraine.svg">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta content="PokeTranslate" property=og:title>
|
||||
<meta content="Translate text - Anonymously!" property=twitter:description>
|
||||
<meta content="https://cdn.glitch.global/d68d17bb-f2c0-4bc3-993f-50902734f652/aa70111e-5bcd-4379-8b23-332a33012b78.image.png?v=1701898829884" property="og:image" />
|
||||
<meta content=summary_large_image name=twitter:card>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline'">
|
||||
<meta name="referrer" content="no-referrer">
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
<style>
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.wrap {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.wrap.languages {
|
||||
flex-wrap: nowrap;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#could_not_switch_languages_text {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.item {
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
border-radius:1em;
|
||||
}
|
||||
|
||||
.item-wrapper {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
width: 450px;
|
||||
margin: 5px 10px;
|
||||
}
|
||||
|
||||
|
||||
.language,
|
||||
.switch_languages {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.language {
|
||||
margin: 0px 10px;
|
||||
}
|
||||
|
||||
.switch_languages {
|
||||
margin: 0px 5px;
|
||||
}
|
||||
|
||||
#switchbutton {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
button {
|
||||
font-size: 1rem;
|
||||
padding: 4px 10px;
|
||||
border: 2px solid #888888;
|
||||
}
|
||||
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
width: 100%;
|
||||
font-size: 1rem;
|
||||
padding: 4px;
|
||||
border: 2px solid #888888;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
height: 5rem;
|
||||
font-family: sans-serif;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
input:focus,
|
||||
select:focus,
|
||||
textarea:focus,
|
||||
button:focus {
|
||||
border-color: #478061;
|
||||
outline: 1px solid #478061;
|
||||
}
|
||||
|
||||
|
||||
body {
|
||||
justify-content: center;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
#definitions_and_translations {
|
||||
display: grid;
|
||||
margin: auto;
|
||||
width: 1100px;
|
||||
gap: 10px;
|
||||
grid-template-areas: "definitions translations";
|
||||
|
||||
}
|
||||
|
||||
.def_type {
|
||||
color: #007979;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.syn {
|
||||
color: #804700;
|
||||
}
|
||||
|
||||
.syn_type {
|
||||
color: #007979;
|
||||
}
|
||||
|
||||
.use_in_sentence {
|
||||
color: #009902;
|
||||
}
|
||||
|
||||
.definitions li:not(:last-child) {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1200px) {
|
||||
#definitions_and_translations {
|
||||
display: grid;
|
||||
width: 90vw;
|
||||
grid-template-areas:
|
||||
"definitions definitions"
|
||||
"translations translations";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
div.definitions {
|
||||
grid-area: definitions;
|
||||
}
|
||||
|
||||
div.translations {
|
||||
grid-area: translations;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #212529;
|
||||
color: #f8f9fa;
|
||||
}
|
||||
|
||||
#could_not_switch_languages_text {
|
||||
color: #F13333;
|
||||
}
|
||||
|
||||
a:visited {
|
||||
color: #9759f6;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #599bf6;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
input,
|
||||
select,
|
||||
button,
|
||||
textarea {
|
||||
background-color: #131618;
|
||||
border-color: #495057;
|
||||
color: #f8f9fa;
|
||||
}
|
||||
|
||||
.def_type {
|
||||
color: cyan;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.syn {
|
||||
color: burlywood;
|
||||
}
|
||||
|
||||
.syn_type {
|
||||
color: cyan;
|
||||
}
|
||||
|
||||
.use_in_sentence {
|
||||
color: yellow;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<% if (isMobile) { %>
|
||||
<style>
|
||||
body {
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
<% } %>
|
||||
|
||||
<% if (!isMobile) { %>
|
||||
<style>
|
||||
body {
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
<% } %>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div style="border-radius: 3em;background: #1a1a1a;padding: 1em;display: flex;flex-direction: column;height: fit-content;align-self: center;margin-top: 6em;">
|
||||
|
||||
<header class="center"><h1>PokeTranslate</h1></header>
|
||||
|
||||
<form action="/translate" method="GET" id="translation-form">
|
||||
|
||||
<!-- from and to language -->
|
||||
<div class="wrap languages">
|
||||
<div class="language">
|
||||
|
||||
<% const languageOptions = [
|
||||
{ code: 'autodetect', name: 'Autodetect' },
|
||||
{ code: 'af', name: 'Afrikaans' },
|
||||
{ code: 'sq', name: 'Albanian' },
|
||||
{ code: 'am', name: 'Amharic' },
|
||||
{ code: 'ar', name: 'Arabic' },
|
||||
{ code: 'hy', name: 'Armenian' },
|
||||
{ code: 'as', name: 'Assamese' },
|
||||
{ code: 'ay', name: 'Aymara' },
|
||||
{ code: 'az', name: 'Azerbaijani' },
|
||||
{ code: 'bm', name: 'Bambara' },
|
||||
{ code: 'eu', name: 'Basque' },
|
||||
{ code: 'be', name: 'Belarusian' },
|
||||
{ code: 'bn', name: 'Bengali' },
|
||||
{ code: 'bh', name: 'Bhojpuri' },
|
||||
{ code: 'bs', name: 'Bosnian' },
|
||||
{ code: 'bg', name: 'Bulgarian' },
|
||||
{ code: 'ca', name: 'Catalan' },
|
||||
{ code: 'ceb', name: 'Cebuano' },
|
||||
{ code: 'ny', name: 'Chichewa' },
|
||||
{ code: 'zh-cn', name: 'Chinese (Simplified)' },
|
||||
{ code: 'zh-tw', name: 'Chinese (Traditional)' },
|
||||
{ code: 'co', name: 'Corsican' },
|
||||
{ code: 'hr', name: 'Croatian' },
|
||||
{ code: 'cs', name: 'Czech' },
|
||||
{ code: 'da', name: 'Danish' },
|
||||
{ code: 'dv', name: 'Dhivehi' },
|
||||
{ code: 'doi', name: 'Dogri' },
|
||||
{ code: 'nl', name: 'Dutch' },
|
||||
{ code: 'en', name: 'English' },
|
||||
{ code: 'eo', name: 'Esperanto' },
|
||||
{ code: 'et', name: 'Estonian' },
|
||||
{ code: 'ee', name: 'Ewe' },
|
||||
{ code: 'tl', name: 'Filipino' },
|
||||
{ code: 'fi', name: 'Finnish' },
|
||||
{ code: 'fr', name: 'French' },
|
||||
{ code: 'fy', name: 'Frisian' },
|
||||
{ code: 'gl', name: 'Galician' },
|
||||
{ code: 'ka', name: 'Georgian' },
|
||||
{ code: 'de', name: 'German' },
|
||||
{ code: 'el', name: 'Greek' },
|
||||
{ code: 'gn', name: 'Guarani' },
|
||||
{ code: 'gu', name: 'Gujarati' },
|
||||
{ code: 'ht', name: 'Haitian Creole' },
|
||||
{ code: 'ha', name: 'Hausa' },
|
||||
{ code: 'haw', name: 'Hawaiian' },
|
||||
{ code: 'he', name: 'Hebrew' },
|
||||
{ code: 'hi', name: 'Hindi' },
|
||||
{ code: 'hmn', name: 'Hmong' },
|
||||
{ code: 'hu', name: 'Hungarian' },
|
||||
{ code: 'is', name: 'Icelandic' },
|
||||
{ code: 'ig', name: 'Igbo' },
|
||||
{ code: 'ilo', name: 'Ilocano' },
|
||||
{ code: 'id', name: 'Indonesian' },
|
||||
{ code: 'ga', name: 'Irish' },
|
||||
{ code: 'it', name: 'Italian' },
|
||||
{ code: 'ja', name: 'Japanese' },
|
||||
{ code: 'jv', name: 'Javanese' },
|
||||
{ code: 'kn', name: 'Kannada' },
|
||||
{ code: 'kk', name: 'Kazakh' },
|
||||
{ code: 'km', name: 'Khmer' },
|
||||
{ code: 'rw', name: 'Kinyarwanda' },
|
||||
{ code: 'kok', name: 'Konkani' },
|
||||
{ code: 'ko', name: 'Korean' },
|
||||
{ code: 'kri', name: 'Krio' },
|
||||
{ code: 'ku', name: 'Kurdish (Kurmanji)' },
|
||||
{ code: 'sd', name: 'Sindhi' },
|
||||
{ code: 'si', name: 'Sinhala' },
|
||||
{ code: 'sk', name: 'Slovak' },
|
||||
{ code: 'sl', name: 'Slovenian' },
|
||||
{ code: 'so', name: 'Somali' },
|
||||
{ code: 'es', name: 'Spanish' },
|
||||
{ code: 'su', name: 'Sundanese' },
|
||||
{ code: 'sw', name: 'Swahili' },
|
||||
{ code: 'sv', name: 'Swedish' },
|
||||
{ code: 'tg', name: 'Tajik' },
|
||||
{ code: 'ta', name: 'Tamil' },
|
||||
{ code: 'tt', name: 'Tatar' },
|
||||
{ code: 'te', name: 'Telugu' },
|
||||
{ code: 'th', name: 'Thai' },
|
||||
{ code: 'ti', name: 'Tigrinya' },
|
||||
{ code: 'ts', name: 'Tsonga' },
|
||||
{ code: 'tr', name: 'Turkish' },
|
||||
{ code: 'tk', name: 'Turkmen' },
|
||||
{ code: 'twi', name: 'Twi' },
|
||||
{ code: 'uk', name: 'Ukrainian' },
|
||||
{ code: 'ur', name: 'Urdu' },
|
||||
{ code: 'ug', name: 'Uyghur' },
|
||||
{ code: 'uz', name: 'Uzbek' },
|
||||
{ code: 'vi', name: 'Vietnamese' },
|
||||
{ code: 'cy', name: 'Welsh' },
|
||||
{ code: 'xh', name: 'Xhosa' },
|
||||
{ code: 'yi', name: 'Yiddish' },
|
||||
{ code: 'yo', name: 'Yoruba' },
|
||||
{ code: 'zu', name: 'Zulu' }
|
||||
]; %>
|
||||
|
||||
|
||||
<!-- Source language select -->
|
||||
<select name="from_language" id="from_language" style="margin-right: 1em;border-radius: 1em;padding: 7px;" aria-label="Source language">
|
||||
<% languageOptions.forEach(language => { %>
|
||||
<option value="<%= language.code %>" <%= language.code === (from_language || 'autodetect') ? 'selected' : '' %>><%= language.name %></option>
|
||||
<% }); %>
|
||||
</select>
|
||||
|
||||
|
||||
<!-- Target language select -->
|
||||
<select name="to_language" id="to_language" style="margin-right: 1em;border-radius: 1em;padding: 7px;" aria-label="Target language">
|
||||
<% languageOptions.slice(1).forEach(language => { %>
|
||||
<option value="<%= language.code %>" <%= language.code === to_language ? 'selected' : '' %>><%= language.name %></option>
|
||||
<% }); %>
|
||||
</select>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- text boxes -->
|
||||
<div class="wrap">
|
||||
<div class="item-wrapper">
|
||||
<textarea autofocus class="item" id="input" name="input" dir="auto" placeholder="<%- text %>"><%- text %>
|
||||
</textarea>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="item-wrapper">
|
||||
<textarea id="output" class="translation item" dir="auto" placeholder="Translation" readonly> <%- translation %> </textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<div class="center">
|
||||
<!-- translate button -->
|
||||
<button type="submit" style="border-radius: 1em;padding: 7px;">Translate :3</button>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
|
||||
// this code submits the translation form when pressing Ctrl/Meta+Enter while focussed on the input text field
|
||||
document.getElementById("input").addEventListener("keydown", function(event) {
|
||||
if (event.keyCode === 13 && (event.metaKey || event.ctrlKey)) {
|
||||
document.getElementById("translation-form").submit();
|
||||
}
|
||||
});
|
||||
|
||||
// Auto resize textarea to fit words inside it without need to scroll -- Thanks to: https://stackoverflow.com/a/25621277
|
||||
var input = document.getElementById("input");
|
||||
var output = document.getElementById("output");
|
||||
input.setAttribute("style", "height:" + output.scrollHeight + "px;overflow-y:scroll;");
|
||||
output.setAttribute("style", "height:" + output.scrollHeight + "px;overflow-y:scroll;");
|
||||
input.addEventListener("input", function(e) {
|
||||
this.style.height = 150 + "px";
|
||||
this.style.height = this.scrollHeight + "px";
|
||||
});
|
||||
|
||||
// @license-end
|
||||
</script>
|
||||
<script src="/static/custom-css.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -43,6 +43,20 @@
|
|||
"branch": "dev"
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
"poke.ashley0143.xyz",
|
||||
{
|
||||
"uri": "https://poke.ashley0143.xyz",
|
||||
"CLOUDFLARE": true,
|
||||
"piwik": false,
|
||||
"region": "🇺🇸",
|
||||
"software": {
|
||||
"name": "poketube",
|
||||
"version": "latest",
|
||||
"branch": "dev"
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ app.use(function (req, res, next) {
|
|||
|
||||
app.use(function (_req, res, next) {
|
||||
res.header("Access-Control-Allow-Origin", "*");
|
||||
res.setHeader("Cache-Control", "public, max-age=232337763"); // cache header
|
||||
res.setHeader("Cache-Control", "public, max-age=864000"); // cache header
|
||||
res.setHeader("poketube-cacher", "PROXY_FILES");
|
||||
|
||||
next();
|
||||
|
@ -60,7 +60,7 @@ app.use(function (_req, res, next) {
|
|||
*/
|
||||
const proxy = async (req, res) => {
|
||||
const { fetch } = await import("undici")
|
||||
res.setHeader("Cache-Control", "public, max-age=232337763"); // cache header
|
||||
res.setHeader("Cache-Control", "public, max-age=864000"); // cache header
|
||||
|
||||
try {
|
||||
let url;
|
||||
|
@ -98,9 +98,9 @@ const listener = (req, res) => {
|
|||
app.get("/", (req, res) => {
|
||||
var json = {
|
||||
status: "200",
|
||||
version: "1.2.0",
|
||||
version: "1.3.0",
|
||||
URL_WHITELIST,
|
||||
cache: "max-age-232337763",
|
||||
cache: "max-age-864000",
|
||||
};
|
||||
|
||||
res.json(json);
|
||||
|
|
11
package.json
11
package.json
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "poketube",
|
||||
"version": "20.23",
|
||||
"description": "Libre youtube front-end",
|
||||
"name": "poke",
|
||||
"version": "20.24",
|
||||
"description": "Libre youtube and google front-end",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
"start": "node server.js"
|
||||
|
@ -32,7 +32,8 @@
|
|||
"express-rate-limit": "^7.0.2",
|
||||
"toobusy-js": "^0.5.1",
|
||||
"quick.db": "^7.1.3",
|
||||
"google-it": "^1.6.4"
|
||||
"activitypub-express": "^4.4.1",
|
||||
"duck-duck-scrape": "^2.2.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": "16.x"
|
||||
|
@ -43,7 +44,7 @@
|
|||
"license": "GPL-3.0-or-later",
|
||||
"keywords": [
|
||||
"poketube",
|
||||
"privite",
|
||||
"private",
|
||||
"ytdl"
|
||||
]
|
||||
}
|
127
poke-cli.sh
Normal file
127
poke-cli.sh
Normal file
|
@ -0,0 +1,127 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (C) 2024-20xx Poke! (https://codeberg.org/ashley/poke)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
function display_help {
|
||||
echo "Usage: $0 <search_query>"
|
||||
echo " --help you are here lol"
|
||||
echo " --version version information."
|
||||
echo " --license license stuff"
|
||||
}
|
||||
|
||||
function display_version {
|
||||
echo "poke-cli version 1.2
|
||||
|
||||
Play videos from your terminal!
|
||||
https://codeberg.org/ashley/poke
|
||||
|
||||
Copyright (C) 2024-202x Poke
|
||||
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
|
||||
This is free software: you are free to change and redistribute it.
|
||||
There is NO WARRANTY, to the extent permitted by law.
|
||||
"
|
||||
}
|
||||
|
||||
# Display license information
|
||||
function display_license {
|
||||
cat <<EOF
|
||||
|
||||
Poke-CLI for GNU/Linux systems
|
||||
|
||||
Copyright (C) Poke 2024-20xx
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
case $1 in
|
||||
--help)
|
||||
display_help
|
||||
exit 0
|
||||
;;
|
||||
--version)
|
||||
display_version
|
||||
exit 0
|
||||
;;
|
||||
--license)
|
||||
display_license
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "Usage: $0 <search_query> / see --help for more info :D"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# config
|
||||
poke_instance="https://poketube.fun"
|
||||
invid_api_url="https://invid-api.poketube.fun"
|
||||
|
||||
search_query=$1
|
||||
|
||||
player="mpv"
|
||||
|
||||
|
||||
if ! command -v jq &> /dev/null && ! command -v gojq &> /dev/null; then
|
||||
echo "Error: jq or gojq not found. Please install them to run the script."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
json_data=$(curl -s "$invid_api_url/api/v1/search?q=${search_query// /+}&type=video")
|
||||
|
||||
video_count=$(echo "$json_data" | jq -r '. | length')
|
||||
if [ $video_count -eq 0 ]; then
|
||||
echo "Nyo videos found for the given search query ;_;"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Select a vid to play:"
|
||||
echo
|
||||
|
||||
for i in $(seq 0 $(($video_count - 1))); do
|
||||
title=$(echo "$json_data" | jq -r ".[$i].title")
|
||||
author=$(echo "$json_data" | jq -r ".[$i].author")
|
||||
echo "[$(($i + 1))] $title by $author"
|
||||
done
|
||||
|
||||
read -p "Enter the thingy umm number of the video to play (1-$video_count): " selection
|
||||
|
||||
if ! [[ "$selection" =~ ^[1-9][0-9]*$ ]] || [ "$selection" -lt 1 ] || [ "$selection" -gt "$video_count" ]; then
|
||||
echo "enter a number between 1 and $video_count lol"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
video_url=$(echo "$json_data" | jq -r ".[$(($selection - 1))].videoId")
|
||||
|
||||
echo "Starting $player..."
|
||||
echo "please wait - this may take some time lol..."
|
||||
|
||||
$player "$poke_instance/watch?v=$video_url"
|
||||
|
|
@ -16,21 +16,36 @@
|
|||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
-->
|
||||
<!DOCTYPE html><html>
|
||||
<head>
|
||||
<title>PokeTube</title>
|
||||
</head>
|
||||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<title>Poke - No interenet!1!1!1!111!</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="error-page">
|
||||
<div id="error-page-content" align="center">
|
||||
<h1 style="color:#fff;font-family:'PokeTube Flex',sans-serif;font-weight:900;white-space:yes;font-style: italic;font-size: 45px;" align="center">Oh no ;-;</h1>
|
||||
<h3>Looks like you're offline, check your internet connection and try again.</h3>
|
||||
<h1 style="color:#fff;font-family:'PokeTube Flex',sans-serif;font-weight:900;white-space:yes;font-style: italic;font-size: 45px;" align="center">Oh nyo >~<</h1>
|
||||
<h3 style="font-family: sans-serif;">Connectivity to the server has been lost qwq <br> Seems like you're offline - u check your internet connection and try again</h3><br>
|
||||
<p>or u can just view poke!'s <a href="https://status.poketube.fun">status page</a> yk~ </p>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<style>
|
||||
.downnav {
|
||||
position: fixed;
|
||||
padding:10px;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
overflow: hidden;
|
||||
z-index: 1;
|
||||
color:#fff;
|
||||
background-color: #0f0f0f;
|
||||
}
|
||||
|
||||
body{
|
||||
background:#111;
|
||||
margin: auto;
|
||||
|
@ -38,10 +53,11 @@
|
|||
}
|
||||
p,a,h3{
|
||||
text-align:center;
|
||||
font-family: sans-serif;
|
||||
color:#fff;
|
||||
}
|
||||
nav,error-page,div{
|
||||
justify-content: center;
|
||||
background: #111
|
||||
}
|
||||
</style>
|
||||
</style></body></html>
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// @license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-3.0-or-later
|
||||
|
||||
'use strict';
|
||||
|
||||
var cacheVersion = 1;
|
||||
|
@ -32,3 +34,5 @@ this.addEventListener('fetch', event => {
|
|||
);
|
||||
}
|
||||
});
|
||||
|
||||
// @license-end
|
17
server.js
17
server.js
|
@ -2,7 +2,7 @@
|
|||
|
||||
PokeTube is an Free/Libre youtube front-end. this is our main file.
|
||||
|
||||
Copyright (C) 2021-2023 POKETUBE (https://codeberg.org/Ashley/poketube)
|
||||
Copyright (C) 2021-2024 POKETUBE (https://codeberg.org/Ashley/poketube)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -35,7 +35,7 @@
|
|||
const u = await media_proxy();
|
||||
initlog("Loading...");
|
||||
initlog(
|
||||
"[Welcome] Welcome To PokeTube :3 " +
|
||||
"[Welcome] Welcome To Poke - The ultimate privacy app - :3 " +
|
||||
"Running " +
|
||||
`Node ${process.version} - V8 v${
|
||||
process.versions.v8
|
||||
|
@ -65,8 +65,8 @@
|
|||
|
||||
|
||||
const limiter = rateLimit({
|
||||
windowMs:45 * 1000, // 30 Seconds
|
||||
max: 886, // limit each IP to 870 requests per windowMs
|
||||
windowMs:45 * 1000, // 45 Seconds
|
||||
max: 886, // limit each IP to 866 requests per windowMs
|
||||
});
|
||||
|
||||
var app = modules.express();
|
||||
|
@ -101,6 +101,7 @@ toobusy.maxLag(3500);
|
|||
});
|
||||
|
||||
toobusy.onLag(function(currentLag) {
|
||||
process.exit(1);
|
||||
console.log("Event loop lag detected! Latency: " + currentLag + "ms");
|
||||
});
|
||||
|
||||
|
@ -136,6 +137,9 @@ toobusy.maxLag(3500);
|
|||
}
|
||||
res.header("secure-poketube-instance", "1");
|
||||
|
||||
// opt out of googles "FLOC" bullcrap :p See https://spreadprivacy.com/block-floc-with-duckduckgo/
|
||||
res.header("Permissions-Policy", "interest-cohort=()")
|
||||
res.header("software-name", "poke")
|
||||
next();
|
||||
});
|
||||
|
||||
|
@ -157,8 +161,9 @@ toobusy.maxLag(3500);
|
|||
|
||||
app.use(function (req, res, next) {
|
||||
res.header("X-PokeTube-Youtube-Client-Name", "1");
|
||||
res.header("X-PokeTube-Youtube-Client-Version", "2.20210721.00.00");
|
||||
res.header("X-PokeTube-Speeder", "6 seconds no cache, 780ms w/cache");
|
||||
res.header("Hey-there", "Do u wanna help poke? contributons are welcome :3 https://codeberg.org/Ashley/poke")
|
||||
res.header("X-PokeTube-Youtube-Client-Version", "2.20240111.00.00");
|
||||
res.header("X-PokeTube-Speeder", "3 seconds no cache, 280ms w/cache");
|
||||
if (req.url.match(/^\/(css|js|img|font)\/.+/)) {
|
||||
res.setHeader(
|
||||
"Cache-Control",
|
||||
|
|
|
@ -130,8 +130,13 @@ module.exports = function (app, config, renderTemplate) {
|
|||
|
||||
if (req.params.v && /[a-zA-Z0-9]+/.test(req.params.v)) {
|
||||
const isvld = await core.isvalidvideo(req.params.v);
|
||||
if (isvld) {
|
||||
if (isvld && req.params.v.length >= 10) {
|
||||
return res.redirect(`/watch?v=${req.params.v}`);
|
||||
} else {
|
||||
return renderTemplate(res, req, "404.ejs", {
|
||||
isOldWindows,
|
||||
random
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,12 +29,12 @@ function getJson(str) {
|
|||
const pkg = require("../../../package.json");
|
||||
const cnf = require("../../../config.json");
|
||||
|
||||
const verfull = "v23.1311-JeSsIcA-MAJOR-stable-dev-nonLTS-git-MTcwMDI5ODc4OQ==";
|
||||
const versmol = "v23.1311-JeSsIcA"
|
||||
const verfull = "v24.2801-JeSsIcA-MAJOR-stable-dev-nonLTS-git-MTcwNjQzMTc0OQ==";
|
||||
const versmol = "v24.2801-JeSsIcA"
|
||||
const branch = "dev/master";
|
||||
const codename = "jessica";
|
||||
const versionnumber = "272";
|
||||
const relaseunixdate = "MTcwMDI5ODc4OQ=="
|
||||
const versionnumber = "273";
|
||||
const relaseunixdate = "MTcwNjQzMTc0OQ=="
|
||||
const updatequote = "Empty your cup so that it may be filled; become devoid to gain totality. - Bruce Lee"
|
||||
|
||||
|
||||
|
@ -52,7 +52,7 @@ module.exports = function (app, config, renderTemplate) {
|
|||
});
|
||||
|
||||
app.get("/vi/:v/:t", async function (req, res) {
|
||||
var url = `https://invidious.snopyta.org/vi/${req.params.v}/${req.params.t}`
|
||||
var url = `https://vid.puffyan.us/vi/${req.params.v}/${req.params.t}`
|
||||
|
||||
let f = await modules.fetch(url + `?cachefixer=${btoa(Date.now())}`, {
|
||||
method: req.method,
|
||||
|
@ -63,7 +63,7 @@ module.exports = function (app, config, renderTemplate) {
|
|||
});
|
||||
|
||||
app.get("/avatars/:v", async function (req, res) {
|
||||
var url = `https://invidious.snopyta.org/ggpht/${req.params.v}`;
|
||||
var url = `https://vid.puffyan.us/ggpht/${req.params.v}`;
|
||||
|
||||
let f = await modules.fetch(url + `?cachefixer=${btoa(Date.now())}`, {
|
||||
method: req.method,
|
||||
|
@ -73,7 +73,7 @@ app.get("/avatars/:v", async function (req, res) {
|
|||
});
|
||||
|
||||
app.get("/ggpht/:v", async function (req, res) {
|
||||
var url = `https://invidious.snopyta.org/ggpht/${req.params.v}`;
|
||||
var url = `https://vid.puffyan.us/ggpht/${req.params.v}`;
|
||||
|
||||
let f = await modules.fetch(url + `?cachefixer=${btoa(Date.now())}`, {
|
||||
method: req.method,
|
||||
|
@ -84,7 +84,7 @@ app.get("/avatars/:v", async function (req, res) {
|
|||
|
||||
|
||||
app.get("/avatars/ytc/:v", async function (req, res) {
|
||||
var url = `https://invidious.snopyta.org/ggpht/ytc/${req.params.v.replace("ytc", "")}`;
|
||||
var url = `https://vid.puffyan.us/ggpht/ytc/${req.params.v.replace("ytc", "")}`;
|
||||
|
||||
let f = await modules.fetch(url + `?cachefixer=${btoa(Date.now())}`, {
|
||||
method: req.method,
|
||||
|
@ -114,7 +114,7 @@ app.get("/avatars/:v", async function (req, res) {
|
|||
var format = "mp3";
|
||||
}
|
||||
|
||||
const url = `https://tube-proxy.poketube.fun/proxy/media/${v}/${q}`;
|
||||
const url = `https://tube.kuylar.dev/proxy/media/${v}/${q}`;
|
||||
|
||||
res.redirect(url);
|
||||
});
|
||||
|
|
|
@ -50,9 +50,10 @@ const ChannelTabs = {
|
|||
shorts: "c2hvcnRz",
|
||||
videos: "dmlkZW9z",
|
||||
streams: "c3RyZWFtcw==", // or "live"
|
||||
channels:"Y2hhbm5lbHM=",
|
||||
store:"c3RvcmU=",
|
||||
released:"cmVsZWFzZWQ="
|
||||
channels: "Y2hhbm5lbHM=",
|
||||
store: "c3RvcmU=",
|
||||
released: "cmVsZWFzZWQ=",
|
||||
playlist: "cGxheWxpc3Rz",
|
||||
};
|
||||
|
||||
module.exports = function (app, config, renderTemplate) {
|
||||
|
@ -84,14 +85,16 @@ module.exports = function (app, config, renderTemplate) {
|
|||
res.json(ChannelTabs);
|
||||
});
|
||||
|
||||
|
||||
app.get("/search", async (req, res) => {
|
||||
const query = req.query.query;
|
||||
const tab = req.query.tab;
|
||||
const { fetch } = await import("undici");
|
||||
|
||||
const search = require("google-it");
|
||||
var media_proxy = config.media_proxy;
|
||||
|
||||
if (req.useragent.source.includes("Pardus")) {
|
||||
var media_proxy = "https://media-proxy.ashley0143.xyz";
|
||||
}
|
||||
var uaos = req.useragent.os;
|
||||
var IsOldWindows;
|
||||
|
||||
|
@ -132,9 +135,13 @@ module.exports = function (app, config, renderTemplate) {
|
|||
try {
|
||||
const headers = {};
|
||||
|
||||
const xmlData = await fetch(`https://invid-api.poketube.fun/api/v1/search?q=${encodeURIComponent(
|
||||
const xmlData = await fetch(
|
||||
`https://invid-api.poketube.fun/api/v1/search?q=${encodeURIComponent(
|
||||
query
|
||||
)}&page=${encodeURIComponent(continuation)}&date=${date}&type=${type}&duration=${duration}&sort=${sort}&hl=en+gb`)
|
||||
)}&page=${encodeURIComponent(
|
||||
continuation
|
||||
)}&date=${date}&type=${type}&duration=${duration}&sort=${sort}&hl=en+gb`
|
||||
)
|
||||
.then((res) => res.text())
|
||||
.then((txt) => getJson(txt));
|
||||
|
||||
|
@ -148,7 +155,7 @@ module.exports = function (app, config, renderTemplate) {
|
|||
IsOldWindows,
|
||||
tab,
|
||||
continuation,
|
||||
media_proxy_url: config.media_proxy,
|
||||
media_proxy_url: media_proxy,
|
||||
results: "",
|
||||
q: query,
|
||||
summary: "",
|
||||
|
@ -159,12 +166,24 @@ module.exports = function (app, config, renderTemplate) {
|
|||
}
|
||||
});
|
||||
|
||||
app.get("/im-feeling-lucky", function (req, res) {
|
||||
res.send("WIP");
|
||||
});
|
||||
|
||||
app.get("/web", async (req, res) => {
|
||||
const query = req.query.query;
|
||||
const tab = req.query.tab;
|
||||
|
||||
const search = require("google-it");
|
||||
const { fetch } = await import("undici");
|
||||
|
||||
const search = await fetch(
|
||||
`https://4get.sudovanilla.com/api/v1/web?s=${query}`
|
||||
);
|
||||
const web = getJson(await search.text());
|
||||
|
||||
if (req.query.lucky === "true") {
|
||||
res.redirect("/im-feeling-lucky?query=" + query);
|
||||
}
|
||||
var uaos = req.useragent.os;
|
||||
var IsOldWindows;
|
||||
|
||||
|
@ -199,7 +218,8 @@ module.exports = function (app, config, renderTemplate) {
|
|||
let continuation = req.query.continuation || "";
|
||||
|
||||
try {
|
||||
search({ query: `${req.query.query}` }).then((results) => {
|
||||
const results = web.web;
|
||||
|
||||
renderTemplate(res, req, "search-web.ejs", {
|
||||
j: "",
|
||||
IsOldWindows,
|
||||
|
@ -211,7 +231,6 @@ module.exports = function (app, config, renderTemplate) {
|
|||
q: query,
|
||||
summary: "",
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(`Error while searching for '${query}':`, error);
|
||||
res.redirect("/");
|
||||
|
@ -221,7 +240,21 @@ module.exports = function (app, config, renderTemplate) {
|
|||
app.get("/channel/", async (req, res) => {
|
||||
const { fetch } = await import("undici");
|
||||
try {
|
||||
const ID = req.query.id;
|
||||
var media_proxy = config.media_proxy;
|
||||
|
||||
if (req.useragent.source.includes("Pardus")) {
|
||||
var media_proxy = "https://media-proxy.ashley0143.xyz";
|
||||
}
|
||||
|
||||
var ID = req.query.id;
|
||||
|
||||
if (ID.endsWith("@youtube.com")) {
|
||||
ID = ID.slice(0, -"@youtube.com".length);
|
||||
}
|
||||
|
||||
if (ID.endsWith("@poketube.fun")) {
|
||||
ID = ID.slice(0, -"@poketube.fun".length);
|
||||
}
|
||||
const tab = req.query.tab;
|
||||
const cache = {};
|
||||
|
||||
|
@ -268,17 +301,33 @@ module.exports = function (app, config, renderTemplate) {
|
|||
const communityUrl = `${apiUrl}${atob(
|
||||
ChannelTabs.community
|
||||
)}/${ID}/?hl=en-US`;
|
||||
const PlaylistUrl = `${apiUrl}${atob(
|
||||
ChannelTabs.playlist
|
||||
)}/${ID}/?hl=en-US`;
|
||||
|
||||
const channelINVUrl = `${apiUrl}${ID}/`;
|
||||
|
||||
var [tj, shorts, stream, c, cinv] = await Promise.all([
|
||||
var [tj, shorts, playlist, stream, c, cinv] = await Promise.all([
|
||||
getChannelData(channelUrl),
|
||||
getChannelData(shortsUrl),
|
||||
getChannelData(PlaylistUrl),
|
||||
getChannelData(streamUrl),
|
||||
getChannelData(communityUrl),
|
||||
getChannelData(channelINVUrl),
|
||||
]);
|
||||
|
||||
function getThumbnailUrl(video) {
|
||||
const maxresDefaultThumbnail = video.videoThumbnails.find(
|
||||
(thumbnail) => thumbnail.quality === "maxresdefault"
|
||||
);
|
||||
|
||||
if (maxresDefaultThumbnail) {
|
||||
return `https://vid.puffyan.us/vi/${video.videoId}/maxresdefault.jpg`;
|
||||
} else {
|
||||
return `https://vid.puffyan.us/vi/${video.videoId}/hqdefault.jpg`;
|
||||
}
|
||||
}
|
||||
|
||||
cache[ID] = {
|
||||
result: {
|
||||
tj,
|
||||
|
@ -315,13 +364,15 @@ module.exports = function (app, config, renderTemplate) {
|
|||
cinv,
|
||||
convert,
|
||||
turntomins,
|
||||
media_proxy_url: config.media_proxy,
|
||||
media_proxy_url: media_proxy,
|
||||
dnoreplace,
|
||||
getThumbnailUrl,
|
||||
continuation,
|
||||
wiki: "",
|
||||
getFirstLine,
|
||||
isMobile: req.useragent.isMobile,
|
||||
about,
|
||||
playlist,
|
||||
subs:
|
||||
typeof subscribers === "string"
|
||||
? subscribers.replace("subscribers", "")
|
||||
|
|
|
@ -27,6 +27,13 @@ const sha384 = modules.hash;
|
|||
const notice =
|
||||
"/* the code is Licensed in gpl-3.0-or-later. This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. See the GNU General Public License for more detailsYou should have received a copy of the GNU General Public Licensealong with this program. If not, see <https://www.gnu.org/licenses/>. - add the param nomin to view source code. (eg poketube.fun/css/poketube.css?nomin=true) */";
|
||||
|
||||
function getJson(str) {
|
||||
try {
|
||||
return JSON.parse(str);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
module.exports = function (app, config, renderTemplate) {
|
||||
var html_location = "./css/";
|
||||
var location_pwa = "./pwa/";
|
||||
|
@ -67,10 +74,61 @@ module.exports = function (app, config, renderTemplate) {
|
|||
}
|
||||
});
|
||||
|
||||
app.get("/rewind", function (req, res) {
|
||||
renderTemplate(res, req, "rewind.ejs");
|
||||
});
|
||||
|
||||
app.get("/translate", async function (req, res) {
|
||||
const { fetch } = await import("undici");
|
||||
|
||||
const api_url = "https://simplytranslate.org/api/translate";
|
||||
|
||||
// Fetch translation data
|
||||
const translationResponse = await fetch(
|
||||
`${api_url}?from=${req.query.from_language}&to=${req.query.to_language}&text=${req.query.input}&engine=google`
|
||||
);
|
||||
|
||||
// Check if the request was successful (status code 200)
|
||||
const translationData = await translationResponse.json();
|
||||
|
||||
// Extract translated_text from the response
|
||||
const translatedText = translationData.translated_text;
|
||||
|
||||
// Render the template with the translated text
|
||||
renderTemplate(res, req, "translate.ejs", {
|
||||
translation: translatedText,
|
||||
text: req.query.input || "enter text here",
|
||||
from_language: req.query.from_language,
|
||||
to_language: req.query.to_language,
|
||||
isMobile: req.useragent.isMobile,
|
||||
});
|
||||
});
|
||||
|
||||
app.get("/domains", function (req, res) {
|
||||
renderTemplate(res, req, "domains.ejs");
|
||||
});
|
||||
|
||||
app.get("/apps", function (req, res) {
|
||||
renderTemplate(res, req, "apps.ejs");
|
||||
});
|
||||
app.get("/playlist", async function (req, res) {
|
||||
const { fetch } = await import("undici");
|
||||
if (!req.query.list) res.redirect("/");
|
||||
if (req.useragent.isMobile) res.redirect("/");
|
||||
|
||||
const playlist = await fetch(
|
||||
`https://invid-api.poketube.fun/api/v1/playlists/${req.query.list}?hl=en-us`
|
||||
);
|
||||
|
||||
const p = getJson(await playlist.text());
|
||||
var mediaproxy = config.media_proxy;
|
||||
|
||||
renderTemplate(res, req, "playlist.ejs", {
|
||||
p,
|
||||
mediaproxy,
|
||||
});
|
||||
});
|
||||
|
||||
app.get("/license", function (req, res) {
|
||||
renderTemplate(res, req, "license.ejs");
|
||||
});
|
||||
|
@ -95,11 +153,6 @@ module.exports = function (app, config, renderTemplate) {
|
|||
res.sendFile("manifest.json", { root: location_pwa });
|
||||
});
|
||||
|
||||
app.get("/service-worker.js", function (req, res) {
|
||||
res.sendFile("service-worker.js", { root: location_pwa });
|
||||
});
|
||||
|
||||
|
||||
app.get("/customize", function (req, res) {
|
||||
const tab = req.query.tab;
|
||||
|
||||
|
@ -110,6 +163,10 @@ module.exports = function (app, config, renderTemplate) {
|
|||
|
||||
const cssDir = "./css/";
|
||||
|
||||
app.get("/favicon.ico", function (req, res) {
|
||||
res.sendFile("favicon.ico", { root: cssDir });
|
||||
});
|
||||
|
||||
app.get("/css/:id", (req, res) => {
|
||||
const filePath = path.join(cssDir, req.params.id);
|
||||
if (!fs.existsSync(filePath)) {
|
||||
|
@ -123,7 +180,11 @@ module.exports = function (app, config, renderTemplate) {
|
|||
const minimizedCss = new CleanCSS().minify(css).styles;
|
||||
// Serve the minimized CSS file
|
||||
res.header("Content-Type", "text/css");
|
||||
res.send(notice + " " + minimizedCss);
|
||||
res.send(
|
||||
notice +
|
||||
" " +
|
||||
minimizedCss.replace("https://p.poketube.fun", config.p_url)
|
||||
);
|
||||
} else {
|
||||
// Serve the original file
|
||||
res.sendFile(req.params.id, { root: html_location });
|
||||
|
@ -134,20 +195,27 @@ module.exports = function (app, config, renderTemplate) {
|
|||
}
|
||||
});
|
||||
|
||||
app.get("/static/:id", (req, res) => {
|
||||
app.get("/game-hub", function (req, res) {
|
||||
renderTemplate(res, req, "gamehub.ejs", {
|
||||
game: req.query.game,
|
||||
});
|
||||
});
|
||||
app.get("/static/:id", (req, res) => {
|
||||
const id = req.params.id;
|
||||
|
||||
if (id.endsWith(".css")) {
|
||||
res.redirect("/css/" + id);
|
||||
} else if (id.endsWith(".js")) {
|
||||
if (id.endsWith(".bundle.js")) {
|
||||
const jsFiles = ['app.js', 'custom-css.js', 'emojis.js'];
|
||||
const jsFiles = ["app.js", "custom-css.js", "emojis.js"];
|
||||
const combinedContent = jsFiles
|
||||
.map((fileName) => {
|
||||
const filePath = path.join(html_location, fileName);
|
||||
return fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf-8') : '';
|
||||
return fs.existsSync(filePath)
|
||||
? fs.readFileSync(filePath, "utf-8")
|
||||
: "";
|
||||
})
|
||||
.join('\n');
|
||||
.join("\n" + "\n");
|
||||
|
||||
const minimizedJs = require("uglify-js").minify(combinedContent).code;
|
||||
|
||||
|
@ -186,7 +254,5 @@ app.get("/static/:id", (req, res) => {
|
|||
} else {
|
||||
res.sendFile(id, { root: html_location });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
};
|
||||
|
|
|
@ -139,6 +139,11 @@ function lightOrDark(color) {
|
|||
}
|
||||
}
|
||||
|
||||
function isDntEnabled(req) {
|
||||
const dntHeader = req.header('DNT');
|
||||
return dntHeader && (dntHeader === '1' || dntHeader === 'true');
|
||||
}
|
||||
|
||||
function IsInArray(array, id) {
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
if (array[i].id === id) return true;
|
||||
|
@ -178,19 +183,7 @@ module.exports = function (app, config, renderTemplate) {
|
|||
});
|
||||
|
||||
app.get("/watch", async (req, res) => {
|
||||
const {
|
||||
dm,
|
||||
region,
|
||||
hl,
|
||||
v,
|
||||
e,
|
||||
r,
|
||||
f,
|
||||
m,
|
||||
quality: q,
|
||||
a,
|
||||
universe,
|
||||
} = req.query;
|
||||
const { dm, region, hl, v, e, r, f, m, quality: q, a, universe, } = req.query;
|
||||
|
||||
if (!v) {
|
||||
return res.redirect("/");
|
||||
|
@ -212,6 +205,7 @@ module.exports = function (app, config, renderTemplate) {
|
|||
core.video(v, contentlang, contentregion).then((data) => {
|
||||
try {
|
||||
const k = data?.video;
|
||||
const channel_uploads = data?.channel_uploads
|
||||
const json = data?.json;
|
||||
const engagement = data?.engagement;
|
||||
const inv_comments = data?.comments || "Disabled";
|
||||
|
@ -223,6 +217,7 @@ module.exports = function (app, config, renderTemplate) {
|
|||
d = desc.toString().replace(/\n/g, " <br> ");
|
||||
}
|
||||
|
||||
|
||||
const descriptionString = String(inv_vid?.description);
|
||||
|
||||
function extractInfo(regex) {
|
||||
|
@ -238,27 +233,34 @@ module.exports = function (app, config, renderTemplate) {
|
|||
const reddit = extractInfo(REDDIT_REGEX);
|
||||
const instagram = extractInfo(INSTAGRAM_REGEX);
|
||||
|
||||
|
||||
var proxyurl = config.p_url;
|
||||
var vidurl = u.url;
|
||||
var isvidious = u.isInvidiousURL;
|
||||
var mediaproxy = config.media_proxy
|
||||
|
||||
|
||||
if (inv_vid?.genre === "Music") {
|
||||
var vidurl = u.losslessurl;
|
||||
}
|
||||
|
||||
if (inv_vid.author.endsWith(" - Topic")) {
|
||||
var vidurl = "https://eu-proxy.poketube.fun";
|
||||
var isvidious = true;
|
||||
}
|
||||
|
||||
if (req.useragent.source.includes("Pardus")) {
|
||||
var vidurl = "https://yt.sudovanilla.com";
|
||||
var vidurl = "https://iv.ggtyler.dev";
|
||||
var mediaproxy = "https://media-proxy.ashley0143.xyz"
|
||||
var isvidious = true;
|
||||
var isSchoolProxy = "";
|
||||
}
|
||||
|
||||
// unused
|
||||
let badges = "";
|
||||
let comments = "";
|
||||
let nnn = "";
|
||||
|
||||
const dnt_val = isDntEnabled(req)
|
||||
|
||||
if (
|
||||
inv_vid?.error ===
|
||||
"The uploader has not made this video available in your country" ||
|
||||
|
@ -299,15 +301,20 @@ module.exports = function (app, config, renderTemplate) {
|
|||
twitter,
|
||||
k,
|
||||
dm,
|
||||
media_proxy_url: config.media_proxy,
|
||||
proxyurl,
|
||||
media_proxy_url: mediaproxy,
|
||||
instagram,
|
||||
useragent: req.useragent,
|
||||
verify,
|
||||
discord,
|
||||
turntomins,
|
||||
twitch,
|
||||
dnt_val,
|
||||
reddit,
|
||||
channel_uploads,
|
||||
secure,
|
||||
process,
|
||||
isSchoolProxy,
|
||||
sha384,
|
||||
lightOrDark,
|
||||
isMobile: req.useragent.isMobile,
|
||||
|
@ -342,8 +349,7 @@ module.exports = function (app, config, renderTemplate) {
|
|||
const { v, e, r, f, t, quality: q } = req.query;
|
||||
|
||||
try {
|
||||
const info = await modules.fetch("http://ip-api.com/json/");
|
||||
const ip = await info.json();
|
||||
var mediaproxy = config.media_proxy
|
||||
|
||||
const {
|
||||
video: k,
|
||||
|
@ -363,11 +369,13 @@ module.exports = function (app, config, renderTemplate) {
|
|||
const u = await media_proxy(v);
|
||||
const d = desc.toString().replace(/\n/g, " <br> ");
|
||||
const comments = inv_comments || "Disabled";
|
||||
const channel_uploads = data?.channel_uploads
|
||||
|
||||
const templateData = {
|
||||
color,
|
||||
color2,
|
||||
engagement,
|
||||
channel_uploads,
|
||||
u: u.url,
|
||||
video: json,
|
||||
date: k.Video.uploadDate,
|
||||
|
@ -378,11 +386,12 @@ module.exports = function (app, config, renderTemplate) {
|
|||
lightOrDark,
|
||||
isMobile,
|
||||
tj,
|
||||
media_proxy_url: mediaproxy,
|
||||
r,
|
||||
qua: q,
|
||||
isvidious: u.isInvidiousURL,
|
||||
inv: comments,
|
||||
ip,
|
||||
turntomins,
|
||||
convert,
|
||||
linkify,
|
||||
wiki,
|
||||
|
|
|
@ -10,7 +10,6 @@ const { toJson } = require("xml2json");
|
|||
const { curly } = require("node-libcurl");
|
||||
const getdislikes = require("../libpoketube/libpoketube-dislikes.js");
|
||||
const getColors = require("get-image-colors");
|
||||
const wiki = require("wikipedia");
|
||||
|
||||
/**
|
||||
* Class representing PokeTube's core functionality.
|
||||
|
@ -79,8 +78,8 @@ class PokeTubeCore {
|
|||
|
||||
try {
|
||||
const [invComments, videoInfo, videoData] = await Promise.all([
|
||||
fetch(`${this.config.invapi}/comments/${v}?hl=${contentlang}®ion=${contentregion}&h=${btoa(Date.now())}`).then((res) => res.text()),
|
||||
fetch(`${this.config.invapi}/videos/${v}?hl=${contentlang}®ion=${contentregion}&h=${btoa(Date.now())}`).then((res) => res.text()),
|
||||
fetch(`${this.config.invapi_alt}/comments/${v}?hl=${contentlang}®ion=${contentregion}&h=${btoa(Date.now())}`).then((res) => res.text()),
|
||||
fetch(`${this.config.invapi_alt}/videos/${v}?hl=${contentlang}®ion=${contentregion}&h=${btoa(Date.now())}`).then((res) => res.text()),
|
||||
curly
|
||||
.get(`${this.config.tubeApi}video?v=${v}`, {
|
||||
httpHeader: Object.entries(headers).map(([k, v]) => `${k}: ${v}`),
|
||||
|
@ -96,6 +95,11 @@ class PokeTubeCore {
|
|||
const vid = await this.getJson(videoInfo);
|
||||
const { json, video } = videoData;
|
||||
|
||||
const channel_uploads = await fetch(
|
||||
`${this.config.invapi_alt}/channels/${vid.authorId}?hl=${contentlang}®ion=${contentregion}`
|
||||
);
|
||||
const p = this.getJson(await channel_uploads.text());
|
||||
|
||||
if (!vid) {
|
||||
console.log(
|
||||
`Sorry nya, we couldn't find any information about that video qwq`
|
||||
|
@ -115,14 +119,15 @@ class PokeTubeCore {
|
|||
video,
|
||||
vid,
|
||||
comments,
|
||||
channel_uploads:p,
|
||||
engagement: fe.engagement,
|
||||
wiki: "",
|
||||
desc: "",
|
||||
color: await getColors(
|
||||
`https://i.ytimg.com/vi/${v}/hqdefault.jpg?sqp=${this.sqp}`
|
||||
`https://vid.puffyan.us/vi/${v}/hqdefault.jpg?sqp=${this.sqp}`
|
||||
).then((colors) => colors[0].hex()),
|
||||
color2: await getColors(
|
||||
`https://i.ytimg.com/vi/${v}/hqdefault.jpg?sqp=${this.sqp}`
|
||||
`https://vid.puffyan.us/vi/${v}/hqdefault.jpg?sqp=${this.sqp}`
|
||||
).then((colors) => colors[1].hex()),
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
|
@ -166,6 +171,7 @@ class PokeTubeCore {
|
|||
const pokeTubeApiCore = new PokeTubeCore({
|
||||
tubeApi: "https://inner-api.poketube.fun/api/",
|
||||
invapi: "https://invid-api.poketube.fun/api/v1",
|
||||
invapi_alt: "https://iv.ggtyler.dev/api/v1",
|
||||
dislikes: "https://returnyoutubedislikeapi.com/votes?videoId=",
|
||||
t_url: "https://t.poketube.fun/",
|
||||
});
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
PokeTube is a Free/Libre youtube front-end !
|
||||
|
||||
Copyright (C) 2021-2022 POKETUBE
|
||||
Copyright (C) 2021-2024 POKETUBE
|
||||
|
||||
This file is Licensed under LGPL-3.0-or-later. Poketube itself is GPL, Only this file is LGPL.
|
||||
|
||||
|
@ -12,6 +12,11 @@
|
|||
|
||||
*/
|
||||
|
||||
/**
|
||||
* Checks if a string is a valid JSON.
|
||||
* @param {string} str - The string to be checked.
|
||||
* @returns {boolean} - Returns true if the string is a valid JSON, otherwise false.
|
||||
*/
|
||||
function IsJsonString(str) {
|
||||
try {
|
||||
JSON.parse(str);
|
||||
|
@ -21,50 +26,87 @@ function IsJsonString(str) {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a number into a compact string representation using the en-GB locale.
|
||||
* @param {number} value - The number to be converted.
|
||||
* @returns {string} - The compact string representation of the number.
|
||||
*/
|
||||
function convert(value) {
|
||||
return new Intl.NumberFormat("en-GB", {
|
||||
notation: "compact",
|
||||
}).format(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the first line of text before the first occurrence of "<br>".
|
||||
* @param {string} text - The input text.
|
||||
* @returns {string} - The first line of text before "<br>", or the entire text if no "<br>" is found.
|
||||
*/
|
||||
function getFirstLine(text) {
|
||||
var index = text?.indexOf("<br> ");
|
||||
if (index === -1) index = undefined;
|
||||
return text?.substring(0, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Capitalizes the first letter of a string.
|
||||
* @param {string} string - The input string.
|
||||
* @returns {string} - The string with the first letter capitalized.
|
||||
*/
|
||||
function capitalizeFirstLetter(string) {
|
||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts time in seconds to a formatted time string (hh:mm:ss or mm:ss).
|
||||
* If time is 00:00, returns "LIVE".
|
||||
* @param {number} time - The time in seconds.
|
||||
* @returns {string} - The formatted time string.
|
||||
*/
|
||||
function turntomins(time) {
|
||||
var minutes = Math.floor(time / 60);
|
||||
|
||||
var seconds = time - minutes * 60;
|
||||
var hours = Math.floor(time / 3600);
|
||||
var remainingSeconds = time - hours * 3600;
|
||||
var minutes = Math.floor(remainingSeconds / 60);
|
||||
var seconds = remainingSeconds - minutes * 60;
|
||||
|
||||
function str_pad_left(string, pad, length) {
|
||||
return (new Array(length + 1).join(pad) + string).slice(-length);
|
||||
}
|
||||
|
||||
if (hours > 0) {
|
||||
var finalTime =
|
||||
str_pad_left(hours, "0", 2) +
|
||||
":" +
|
||||
str_pad_left(minutes, "0", 2) +
|
||||
":" +
|
||||
str_pad_left(seconds, "0", 2);
|
||||
} else {
|
||||
if (minutes === 0 && seconds === 0) {
|
||||
return "LIVE";
|
||||
} else {
|
||||
var finalTime =
|
||||
str_pad_left(minutes, "0", 2) + ":" + str_pad_left(seconds, "0", 2);
|
||||
}
|
||||
}
|
||||
|
||||
return finalTime;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a random number between min (inclusive) and max (exclusive)
|
||||
* Returns a random floating point number within the specified range.
|
||||
* @param {number} min - The minimum value of the range (inclusive).
|
||||
* @param {number} max - The maximum value of the range (exclusive).
|
||||
* @returns {number} - A random floating point number within the specified range.
|
||||
*/
|
||||
function getRandomArbitrary(min, max) {
|
||||
return Math.random() * (max - min) + min;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a random integer between min (inclusive) and max (inclusive).
|
||||
* The value is no lower than min (or the next integer greater than min
|
||||
* if min isn't an integer) and no greater than max (or the next integer
|
||||
* lower than max if max isn't an integer).
|
||||
* Using Math.round() will give you a non-uniform distribution!
|
||||
* Returns a random integer within the specified range.
|
||||
* @param {number} min - The minimum value of the range (inclusive).
|
||||
* @param {number} max - The maximum value of the range (inclusive).
|
||||
* @returns {number} - A random integer within the specified range.
|
||||
*/
|
||||
function getRandomInt(min, max) {
|
||||
min = Math.ceil(min);
|
||||
|
@ -72,6 +114,12 @@ function getRandomInt(min, max) {
|
|||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases or decreases the brightness of a hexadecimal color code.
|
||||
* @param {string} hex - The hexadecimal color code.
|
||||
* @param {number} percent - The percentage by which to adjust the brightness (positive for increase, negative for decrease).
|
||||
* @returns {string} - The modified hexadecimal color code.
|
||||
*/
|
||||
function increase_brightness(hex, percent){
|
||||
// strip the leading # if it's there
|
||||
hex = hex.replace(/^\s*#|\s*$/g, '');
|
||||
|
@ -91,12 +139,92 @@ function increase_brightness(hex, percent){
|
|||
((0|(1<<8) + b + (256 - b) * percent / 100).toString(16)).substr(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an array to an object with numeric keys.
|
||||
* @param {Array} arr - The input array.
|
||||
* @returns {Object} - The resulting object with numeric keys.
|
||||
*/
|
||||
function toObject(arr) {
|
||||
var rv = {};
|
||||
for (var i = 0; i < arr.length; ++i) if (arr[i] !== undefined) rv[i] = arr[i];
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a color is light or dark.
|
||||
* @param {string} color - The color code in hexadecimal or RGB format.
|
||||
* @returns {string} - Returns "light" if the color is light, otherwise "dark".
|
||||
*/
|
||||
function lightOrDark(color) {
|
||||
// Variables for red, green, blue values
|
||||
var r, g, b, hsp;
|
||||
|
||||
// Check the format of the color, HEX or RGB?
|
||||
if (color.match(/^rgb/)) {
|
||||
// If RGB --> store the red, green, blue values in separate variables
|
||||
color = color.match(
|
||||
/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d+)?))?\)$/
|
||||
);
|
||||
|
||||
r = color[1];
|
||||
g = color[2];
|
||||
b = color[3];
|
||||
} else {
|
||||
// If hex --> Convert it to RGB: http://gist.github.com/983661
|
||||
color = +("0x" + color.slice(1).replace(color.length < 5 && /./g, "$&$&"));
|
||||
|
||||
r = color >> 16;
|
||||
g = (color >> 8) & 255;
|
||||
b = color & 255;
|
||||
}
|
||||
|
||||
// HSP (Highly Sensitive Poo) equation from http://alienryderflex.com/hsp.html
|
||||
hsp = Math.sqrt(0.299 * (r * r) + 0.587 * (g * g) + 0.114 * (b * b));
|
||||
|
||||
// Using the HSP value, determine whether the color is light or dark
|
||||
if (hsp > 127.5) {
|
||||
return "light";
|
||||
} else {
|
||||
return "dark";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an element with a specific ID exists in an array of objects.
|
||||
* @param {Array} array - The array of objects to be searched.
|
||||
* @param {string} id - The ID to search for.
|
||||
* @returns {boolean} - Returns true if the ID exists in the array, otherwise false.
|
||||
*/
|
||||
function IsInArray(array, id) {
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
if (array[i].id === id) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a JSON string into a JavaScript object.
|
||||
* @param {string} str - The JSON string to be parsed.
|
||||
* @returns {(Object|boolean)} - Returns the parsed JavaScript object if successful, otherwise false.
|
||||
*/
|
||||
function getJson(str) {
|
||||
try {
|
||||
return JSON.parse(str);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
IsJsonString,
|
||||
convert,
|
||||
getFirstLine,
|
||||
getRandomArbitrary,
|
||||
getRandomInt,
|
||||
capitalizeFirstLetter,
|
||||
turntomins
|
||||
IsJsonString,
|
||||
convert,
|
||||
getFirstLine,
|
||||
getRandomArbitrary,
|
||||
getJson,
|
||||
lightOrDark,
|
||||
toObject,
|
||||
IsInArray,
|
||||
getRandomInt,
|
||||
capitalizeFirstLetter,
|
||||
turntomins
|
||||
};
|
Loading…
Reference in a new issue