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:
Korbs 2024-02-13 19:55:18 +00:00
commit 0d7aa92eaa
39 changed files with 3942 additions and 790 deletions

19
.drone.yml Normal file
View 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

View file

@ -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

View file

@ -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

View file

@ -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)&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;[Features](#features)&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;[No non-free codec needed](#no-non-free-codec-needed-3)&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;[Hosting Poke~](#hosting-poketube)&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;[Poke community!](#poketube-community)&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;[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)

View file

@ -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,

View file

@ -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) {
event.preventDefault();
popupMenu.style.display = "block";
popupMenu.style.left = event.pageX + "px";
popupMenu.style.top = event.pageY + "px";
});
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

View file

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 515 KiB

View file

@ -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;
@ -198,24 +250,31 @@ a.avatar {
}
.recommended-list {
background-color: var(--div-prim-bg);
border-radius: 1.5em;
background-color: var(--div-prim-bg);
border-radius: 1.5em;
/* padding-right: 24px; */
margin: 10px;
margin-top: 0px;
margin-left: 0px;
height: -moz-fit-content;
height: fit-content;
justify-self: center;
margin-right: -0.9em;
/* width: min-content;*/
border: var(--div-border-color);
border-style: solid;
max-width: 371px;
width: max-content;
margin-top: 0;
margin-left: 0;
height: -moz-fit-content;
height: fit-content;
/* justify-self: center; */
margin-right: -.9em;
border: var(--div-border-color);
border-style: solid;
max-width: 371px;
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 */

View file

@ -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
View 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>

View file

@ -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>
<% if (j.Channel?.Metadata.Banners.Thumbnail) { %>
<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">
<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;
}
@ -328,6 +375,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;
flex-wrap: wrap;
@ -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,9 +880,18 @@ 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") { %>
<% if (tab === "live") { %>
<a href="/channel?id=<%=ID%>" class="tab" style="color:#cfe2f3;">Videos</a>
<% if (Array?.isArray(shorts?.videos)) { %>
@ -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>
<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>
<% if (isMobile) { %>
</p>
<% } %>
<div style="font-weight: bold;color:#fff;margin-left: 10px;">
YouTube removed the about tab ;_; fix for this soon lol
</div>
<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,8 +1555,8 @@ 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");
// Optionally, you can set a default href or display an error message.
anchor.href = "/account-create"
// Optionally, you can set a default href or display an error message.
}
document.getElementById('search').addEventListener('keyup', function () {
@ -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>

View file

@ -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,14 +31,13 @@
<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">
<meta content="#1a1a1a" name="theme-color">
</head>
<style>
.mn {
@ -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

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -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,34 +557,70 @@ 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>
<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>
<% } %>
<% 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>
<% } %>
<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>
<% }) %>
<% 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 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>
<% }) %>
<% } %>
<% } %>
<% 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
View 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=&amp;rs=AOn4CLCLG7gzsIdtlp7ugZJH8YaAHX5bIw&amp;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=&amp;rs=AOn4CLCLG7gzsIdtlp7ugZJH8YaAHX5bIw&amp;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=&amp;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
View 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>

View file

@ -215,15 +215,22 @@
<img src="/css/logo-search.svg?v=393939">
</div>
<div class="search-wrap--home">
<form name="x" id="search_form_homepage" class="search" action="/web" method="get">
<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 />
<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:&quot;poketube flex&quot;;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:&quot;poketube flex&quot;;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:&quot;poketube flex&quot;;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();

View file

@ -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>

View file

@ -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
View 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>

View file

@ -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"
}
}
]
]

View file

@ -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);

View file

@ -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
View 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"

View file

@ -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 &gt;~&lt;</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>

View file

@ -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

View file

@ -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",

View file

@ -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
});
}
}

View file

@ -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);
});

View file

@ -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) {
@ -80,18 +81,20 @@ module.exports = function (app, config, renderTemplate) {
res.redirect(`/watch?v=${v}`);
});
app.get("/api/getchanneltabs", async function (req, res) {
app.get("/api/getchanneltabs", async function (req, res) {
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,15 +135,19 @@ module.exports = function (app, config, renderTemplate) {
try {
const headers = {};
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`)
.then((res) => res.text())
.then((txt) => getJson(txt));
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`
)
.then((res) => res.text())
.then((txt) => getJson(txt));
renderTemplate(res, req, "search.ejs", {
invresults: xmlData,
turntomins,
turntomins,
date,
type,
duration,
@ -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,18 +218,18 @@ module.exports = function (app, config, renderTemplate) {
let continuation = req.query.continuation || "";
try {
search({ query: `${req.query.query}` }).then((results) => {
renderTemplate(res, req, "search-web.ejs", {
j: "",
IsOldWindows,
h: "",
tab,
continuation,
isMobile: req.useragent.isMobile,
results: results,
q: query,
summary: "",
});
const results = web.web;
renderTemplate(res, req, "search-web.ejs", {
j: "",
IsOldWindows,
h: "",
tab,
continuation,
isMobile: req.useragent.isMobile,
results: results,
q: query,
summary: "",
});
} catch (error) {
console.error(`Error while searching for '${query}':`, error);
@ -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", "")

View file

@ -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,15 +74,66 @@ 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");
});
app.get("/map", function (req, res) {
app.get("/map", function (req, res) {
renderTemplate(res, req, "map.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,59 +195,64 @@ module.exports = function (app, config, renderTemplate) {
}
});
app.get("/static/:id", (req, res) => {
const id = req.params.id;
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 combinedContent = jsFiles
.map((fileName) => {
const filePath = path.join(html_location, fileName);
return fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf-8') : '';
})
.join('\n');
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 combinedContent = jsFiles
.map((fileName) => {
const filePath = path.join(html_location, fileName);
return fs.existsSync(filePath)
? fs.readFileSync(filePath, "utf-8")
: "";
})
.join("\n" + "\n");
const minimizedJs = require("uglify-js").minify(combinedContent).code;
const minimizedJs = require("uglify-js").minify(combinedContent).code;
res.header("Content-Type", "text/javascript");
res.send(
"// @license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-3.0-or-later" +
`\n` +
`// Includes app.js, emojis.js, and custom-css.js. Source code can be found for these 3 files in https://codeberg.org/Ashley/poketube/src/branch/main/css/` +
`\n` +
minimizedJs +
`\n` +
"// @license-end"
);
} else {
const filePath = path.join(html_location, id);
res.header("Content-Type", "text/javascript");
res.send(
"// @license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-3.0-or-later" +
`\n` +
`// Includes app.js, emojis.js, and custom-css.js. Source code can be found for these 3 files in https://codeberg.org/Ashley/poketube/src/branch/main/css/` +
`\n` +
minimizedJs +
`\n` +
"// @license-end"
);
} else {
const filePath = path.join(html_location, id);
if (!fs.existsSync(filePath)) {
res.status(404).send("File not found");
return;
if (!fs.existsSync(filePath)) {
res.status(404).send("File not found");
return;
}
const js = fs.readFileSync(filePath, "utf8");
const minimizedJs = require("uglify-js").minify(js).code;
res.header("Content-Type", "text/javascript");
res.send(
"// @license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-3.0-or-later" +
`\n` +
`// Source code can be found in: https://codeberg.org/Ashley/poketube/src/branch/main/css/${id}` +
`\n` +
minimizedJs +
`\n` +
"// @license-end"
);
}
const js = fs.readFileSync(filePath, "utf8");
const minimizedJs = require("uglify-js").minify(js).code;
res.header("Content-Type", "text/javascript");
res.send(
"// @license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-3.0-or-later" +
`\n` +
`// Source code can be found in: https://codeberg.org/Ashley/poketube/src/branch/main/css/${id}` +
`\n` +
minimizedJs +
`\n` +
"// @license-end"
);
} else {
res.sendFile(id, { root: html_location });
}
} else {
res.sendFile(id, { root: html_location });
}
});
});
};

View file

@ -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;
}
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,

View file

@ -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}&region=${contentregion}&h=${btoa(Date.now())}`).then((res) => res.text()),
fetch(`${this.config.invapi}/videos/${v}?hl=${contentlang}&region=${contentregion}&h=${btoa(Date.now())}`).then((res) => res.text()),
fetch(`${this.config.invapi_alt}/comments/${v}?hl=${contentlang}&region=${contentregion}&h=${btoa(Date.now())}`).then((res) => res.text()),
fetch(`${this.config.invapi_alt}/videos/${v}?hl=${contentlang}&region=${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}&region=${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/",
});

View file

@ -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);
}
var finalTime =
str_pad_left(minutes, "0", 2) + ":" + str_pad_left(seconds, "0", 2);
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
};