Compare commits

...

75 Commits

Author SHA1 Message Date
ashley
dcf3b20fac Update html/map.ejs 2025-04-30 21:40:49 +00:00
ashley
b91128ff11 Update html/map.ejs 2025-04-30 21:38:53 +00:00
ashley
46abf16976 Update html/map.ejs 2025-04-30 21:34:37 +00:00
ashley
f9d434903d Update html/map.ejs 2025-04-30 21:27:46 +00:00
ashley
dd5aea5304 Update html/map.ejs 2025-04-30 21:24:37 +00:00
ashley
84b92ae3ac Update html/map.ejs 2025-04-30 21:18:07 +00:00
ashley
f05f3e5b3a Update html/translate.ejs 2025-04-30 17:47:21 +00:00
ashley
b4d7b3da11 stuff 2025-04-30 17:09:01 +00:00
ashley
bb1d09ea20 oops 2025-04-30 16:36:31 +00:00
ashley
d708f964eb add stuff 2025-04-30 16:35:26 +00:00
ashley
e4da5d48d4 Update src/libpoketube/init/pages-api.js 2025-04-30 16:08:06 +00:00
ashley
ac979c3bdc Update src/libpoketube/libpoketube-core.js 2025-04-29 19:55:15 +00:00
ashley
f31ff98a0b Update src/libpoketube/libpoketube-core.js 2025-04-29 19:52:34 +00:00
ashley
cc3922ad0e Update src/libpoketube/libpoketube-core.js 2025-04-29 19:50:23 +00:00
ashley
6e1aecaeb4 Update src/libpoketube/libpoketube-core.js 2025-04-29 19:48:46 +00:00
ashley
c9e8b8f85d Update src/libpoketube/libpoketube-core.js 2025-04-29 19:47:04 +00:00
ashley
99f4d03bbb Update src/libpoketube/libpoketube-core.js 2025-04-29 19:39:14 +00:00
ashley
efd3c59df7 Update package.json 2025-04-29 19:32:33 +00:00
ashley
a5a18ba383 use youtubei 2025-04-29 19:31:18 +00:00
ashley
c531678a18 add stuff 2025-04-27 17:13:14 +00:00
ashley
c9bd527527 Update html/gamehub.ejs 2025-04-27 13:59:24 +00:00
ashley
495367eace Update html/layouts/error-video.ejs 2025-04-27 13:13:34 +00:00
ashley
547f68c882 oops 2025-04-27 12:52:28 +00:00
ashley
6268bdebfb new and improved snake 2025-04-27 12:50:08 +00:00
ashley
7527e49c9c stuff 2025-04-27 11:39:29 +00:00
ashley
7125ecc36e Update html/video-error.ejs 2025-04-27 11:12:17 +00:00
ashley
4058e8ef11 Update html/layouts/error-video.ejs 2025-04-27 11:11:49 +00:00
ashley
0527a9e52f remove 2025-04-27 11:10:19 +00:00
ashley
230d371ced fix this :3 2025-04-27 11:05:37 +00:00
ashley
4a8070e65c Update html/gamehub.ejs 2025-04-26 23:43:29 +00:00
ashley
556285a8d1 fix game 2025-04-26 23:38:32 +00:00
ashley
3076fb9393 fix stuff stuff 2025-04-26 23:36:34 +00:00
ashley
777e8522b2 Update html/gamehub.ejs 2025-04-26 23:32:25 +00:00
ashley
efe0f7d758 Update html/gamehub.ejs 2025-04-26 23:28:37 +00:00
ashley
38094732ba Update html/gamehub.ejs 2025-04-26 23:23:23 +00:00
ashley
b8ce39698a oopsie 2025-04-26 23:19:40 +00:00
ashley
4519933c9e Update html/gamehub.ejs 2025-04-26 23:16:33 +00:00
ashley
18635eca02 Update src/libpoketube/init/pages-api.js 2025-04-26 22:55:49 +00:00
ashley
2202193d23 remove unused imports 2025-04-26 22:46:59 +00:00
ashley
b1de0358a7 new stuff 2025-04-26 22:45:40 +00:00
ashley
739d64f684 Update html/watch.ejs 2025-04-26 21:57:04 +00:00
ashley
d539547fd3 Update html/watch.ejs 2025-04-26 21:54:06 +00:00
ashley
c5e67b7f05 Update html/watch.ejs 2025-04-26 21:52:43 +00:00
ashley
d31253551c Update html/partials/card.ejs 2025-04-26 21:41:55 +00:00
ashley
0f40a4a152 add replies 2025-04-26 21:37:42 +00:00
ashley
6e627b48a7 addcool stuff 2025-04-26 21:01:06 +00:00
ashley
704b7bc806 Update html/search.ejs 2025-04-23 20:55:15 +00:00
ashley
f77d5e0260 human friendly reason :3 2025-04-23 20:48:27 +00:00
ashley
5ab4cc30a5 Update html/layouts/error-video.ejs 2025-04-23 20:48:07 +00:00
ashley
afa738f8c2 Update html/search.ejs 2025-04-22 23:55:06 +00:00
ashley
3f19854798 Update html/search.ejs 2025-04-22 23:54:03 +00:00
ashley
6801889f64 Update html/search.ejs 2025-04-22 23:51:16 +00:00
ashley
ce5428eccb a 2025-04-22 23:48:28 +00:00
ashley
3f66e88dae fix stuff stuff 2025-04-22 23:42:32 +00:00
ashley
7ef352f3cb fix stuff 2025-04-22 23:39:39 +00:00
ashley
38871bba36 Update html/search.ejs 2025-04-22 23:29:48 +00:00
ashley
e755ef3f4c oops 2025-04-22 23:28:23 +00:00
ashley
64433797f3 add alot of cool stuff :3 2025-04-22 23:24:35 +00:00
ashley
3f69953875 add error here :3 2025-04-22 18:48:41 +00:00
ashley
b69b2a590e Update css/maps.js 2025-04-22 18:42:37 +00:00
ashley
3558b47301 update
Signed-off-by: ashley <iamashley@duck.com>
2025-04-19 22:53:48 +00:00
ashley
acef288683 sorry for weird formatting mobile 2025-04-19 22:47:39 +00:00
ashley
27becd05a6 test1 2025-04-08 17:24:30 +00:00
ashley
0347a9ab94 update :3 2025-04-08 16:57:17 +00:00
ashley
e775e617ed :3 2025-04-08 16:49:38 +00:00
ashley
59dd95fa39 add error here :3 2025-04-07 14:38:31 +00:00
ashley
fd1f3ea864 Update src/libpoketube/init/pages-static.js 2025-04-06 19:40:09 +00:00
ashley
310ffb643c Update src/libpoketube/init/pages-channel-and-download.js 2025-04-06 19:36:45 +00:00
ashley
4bf687b4a3 Update src/libpoketube/init/pages-channel-and-download.js 2025-04-06 19:33:16 +00:00
ashley
4acf840d80 Update src/libpoketube/init/pages-api.js 2025-04-06 19:27:37 +00:00
ashley
4b33b38e1f p2 2025-04-06 19:22:36 +00:00
ashley
7188bfdf03 Update .gitignore 2025-04-06 19:16:39 +00:00
ashley
440431abbd Update config.json.example 2025-04-06 19:16:18 +00:00
ashley
172a7175ec add useragent to config 2025-04-06 19:02:54 +00:00
ashley
b5e09f60eb add useragent : p1 2025-04-06 19:02:08 +00:00
20 changed files with 3106 additions and 2052 deletions

1
.gitignore vendored
View File

@ -3,3 +3,4 @@ yarn.lock
package-lock.json
.env
json.sqlite
config.json

View File

@ -4,6 +4,7 @@
"dislikes": "https://returnyoutubedislikeapi.com/votes?videoId=",
"invchannel": "https://invid-api.poketube.fun/api/v1",
"p_url":"https://p.poketube.fun",
"useragent":"PokeTube/2.0.0 (GNU/Linux; Android 14; Trisquel 11; poketube-vidious; like FreeTube)",
"media_proxy": "https://image-proxy.poketube.fun",
"videourl":"https://eu-proxy.poketube.fun",
"email_main_url":"https://email-server.poketube.fun",

View File

@ -1,33 +1 @@
var bbox = "?bbox=-165.76171875000003%2C-3.864254615721396%2C30.410156250000004%2C72.44879155730672&amp;layer=mapnik"
var iframe = document.getElementById('myFrame');
iframe.src=`https://www.openstreetmap.org/export/embed.html${bbox}`
iframe.addEventListener('load', function() {
var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
var links = iframeDocument.getElementsByTagName('a');
for (var i = 0; i < links.length; i++) {
links[i].addEventListener('click', function(event) {
var url = event.target.href;
if (url.includes('www.openstreetmap.org')) {
event.preventDefault();
iframe.src = url;
window.history.pushState(null, '', url);
} else {
window.location.href = url;
}
});
}
});
window.onpopstate = function(event) {
iframe.src = window.location.href;
};
iframe.addEventListener('load', function() {
var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
var elements = iframeDocument.querySelectorAll('[style*="//dka575ofm4ao0.cloudfront.net"]');
for (var i = 0; i < elements.length; i++) {
var style = elements[i].style.backgroundImage;
var newStyle = style.replace('//dka575ofm4ao0.cloudfront.net', 'https://p.poketube.fun/https://dka575ofm4ao0.cloudfront.net');
elements[i].style.backgroundImage = newStyle;
}
});
(function(){const _0x5a3c=["P2Jib3g9LTE2NS43NjE3MTg3NTAwMDAwMyUyQy0zLjg2NDI1NDYxNTcyMTM5NiUyQzMwLjQxMDE1NjI1MDAwMDAwNCUyQzcyLjQ0ODc5MTU1NzMwNjcyJmxheWVyPW1hcG5paw==","aHR0cHM6Ly93d3cub3BlbnN0cmVldG1hcC5vcmcvZXhwb3J0L2VtYmVkLmh0bWw=","d3d3Lm9wZW5zdHJlZXRtYXAub3Jn"];function _0x99f2(i){return atob(_0x5a3c[i])}async function _0x4f2a(){const bbox=_0x99f2(0);const base=_0x99f2(1);const url=base+bbox;const resp=await fetch(url,{credentials:'include'});const txt=await resp.text();const blob=new Blob([txt],{type:'text/html'});const iframe=document.getElementById('myFrame');iframe.src=URL.createObjectURL(blob);iframe.addEventListener('load',()=>{const doc=iframe.contentDocument||iframe.contentWindow.document;Array.from(doc.querySelectorAll('a')).forEach(a=>a.addEventListener('click',_linkHandler));Array.from(doc.querySelectorAll('*')).forEach(el=>{const bg=el.style.backgroundImage;if(bg.includes('//dka575ofm4ao0.cloudfront.net')){el.style.backgroundImage=bg.replace(/\/\/dka575ofm4ao0\.cloudfront\.net/g,m=>`https://p.poketube.fun/https://dka575ofm4ao0.cloudfront.net`)}})});window.history=new Proxy(window.history,{get(target,prop){if(prop==='pushState'){return(...args)=>{if(args[2]){document.getElementById('myFrame').src=args[2]}return target.pushState.apply(target,args)}}return Reflect.get(target,prop)}});window.addEventListener('popstate',()=>{document.getElementById('myFrame').src=location.href})}function _linkHandler(e){const h=e.target.href;if(h.includes(_0x99f2(2))){e.preventDefault();document.getElementById('myFrame').src=h;window.history.pushState({},'',h)}else{window.location.href=h}}_0x4f2a().catch(console.error)})()};);

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@
This Source Code Form is subject to the terms of the GNU General Public License:
Copyright (C) 2021-2024 Poke (https://codeberg.org/Ashley/poke)
Copyright (C) 2021-2025 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
@ -33,14 +33,14 @@
<link href=/css/yt-ukraine.svg?v=7 rel=icon>
<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 -->
<meta content="▶▶ Poke - The privacy app of your dreams!" property=og:title>
<meta content="▶▶ Poke - The only (good) front-end in the world!" property=og:title>
<% if(embedtype === "woke") { %>
<meta content="Poke is a 𝔀𝓸𝓴𝓮 software YouTube front-end, search engine, translator, 𝔀𝓸𝓴𝓮 app, and even 𝔀𝓸𝓴𝓮!! Watch 𝔀𝓸𝓴𝓮 videos, search the internet, and do all of that and more 𝔀𝓸𝓴𝓮 in this all-in-one 𝔀𝓸𝓴𝓮 app!!!"
<meta content="Poke is a 𝔀𝓸𝓴𝓮 software YouTube front-end, translator, 𝔀𝓸𝓴𝓮 app, and even 𝔀𝓸𝓴𝓮!! Watch 𝔀𝓸𝓴𝓮 videos, search the internet, and do all of that and more 𝔀𝓸𝓴𝓮 in this all-in-one 𝔀𝓸𝓴𝓮 app!!!"
property="twitter:description">
<meta content="https://cdn.glitch.global/302c6ee0-629f-453b-9024-bad1f8d7be36/9fhFiXJ.png?v=1717357642758"
property="og:image">
<% } else { %>
<meta content="Poke is a free software YouTube front-end, search engine, translator, map app, and more!! Watch silly videos, search the internet, and do all of that and more anonymously in this all-in-one privacy app!!!"
<meta content="Poke is a free software YouTube front-end, translator, map app, and more!! Watch silly videos, search the internet, and do all of that and more anonymously in this all-in-one privacy app!!!"
property="twitter:description">
<meta content="https://cdn.glitch.global/302c6ee0-629f-453b-9024-bad1f8d7be36/poke.png?v=1716216428745"
property="og:image">
@ -117,8 +117,8 @@
<%- include('./partials/header.ejs') %>
<video playsinline muted paused><source src="/bg-480.webm" type="video/webm"/></video>
<div class="landing">
<h1 style="text-align: center;">GUESS WHO'S BACK ...</h1>
<p style="max-width: 800px;text-align: center;margin: auto;margin-bottom: 3em;">...back again.. to save you from big tech and embrace the freedom of privacy!!1! :3 Poke is a free software YouTube front-end, search engine, translator, map app, and more!!1! Watch videos, search the web, and explore without a trace in this all-in-one privacy app!!1! :3</p>
<h1 style="text-align: center;">THE ONLY FRONT-END IN THE WORLD!</h1>
<p style="max-width: 800px;text-align: center;margin: auto;margin-bottom: 3em;">Poke is a free software AD-FREE ! YouTube front-end, translator, map app, and more!!1! Watch videos and explore without a trace in this all-in-one privacy app!!1! :3</p>
<div style="text-align: center; padding: 10px; border-radius: 8px;margin-left: -1em;">
<details>
<summary style="cursor: pointer; color: white; font-size: 18px; text-decoration: underline;">
@ -152,11 +152,14 @@
<img src="/static/Poke-Mobile.jpg" />
</div>
<div>
<h1 style="margin-left: auto;margin-right: auto;text-align: center;margin-bottom: -1em;margin-top: 1em;">TOP 3 REASONS WHY POKE IZ COOL!!</h1>
<p>U can refresh to see other features!!</p>
</div>
<%
const features = [
{ title: "No Tracking and Ads", description: "Poke Has no Trackers or ads - we dont and we wont see the vids ur watching :3", icon: "<svg style='background: #ea6d6d;' width='24px' height='24px' viewBox='0 0 24 24' stroke-width='1.5' fill='none' xmlns='http://www.w3.org/2000/svg' color='#ffffff'><path d='M19.5 16L17.0248 12.6038' stroke='#ffffff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/><path d='M12 17.5V14' stroke='#ffffff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/><path d='M4.5 16L6.96895 12.6124' stroke='#ffffff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/><path d='M3 8C6.6 16 17.4 16 21 8' stroke='#ffffff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/></svg>" },
{ title: "Very Fast", description: "Poke is really ligthweight (both on server and client :3) so you can still use it on poor connections :3", icon: "<svg style='background: #6d8cea;' width='24px' height='24px' stroke-width='1.5' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg' color='#ffffff'><path d='M15 7C16.1046 7 17 6.10457 17 5C17 3.89543 16.1046 3 15 3C13.8954 3 13 3.89543 13 5C13 6.10457 13.8954 7 15 7Z' stroke='#ffffff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/><path d='M12.6133 8.26691L9.30505 12.4021L13.4403 16.5374L11.3727 21.0861' stroke='#ffffff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/><path d='M6.4104 9.5075L9.79728 6.19931L12.6132 8.26692L15.508 11.5752H19.2297' stroke='#ffffff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/><path d='M8.89152 15.7103L7.65095 16.5374H4.34277' stroke='#ffffff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/></svg>" },
{ title: "Speedy", description: "Poke is really ligthweight (both on server and client :3) so you can still use it on poor connections :3", icon: "<svg style='background: #6d8cea;' width='24px' height='24px' stroke-width='1.5' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg' color='#ffffff'><path d='M15 7C16.1046 7 17 6.10457 17 5C17 3.89543 16.1046 3 15 3C13.8954 3 13 3.89543 13 5C13 6.10457 13.8954 7 15 7Z' stroke='#ffffff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/><path d='M12.6133 8.26691L9.30505 12.4021L13.4403 16.5374L11.3727 21.0861' stroke='#ffffff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/><path d='M6.4104 9.5075L9.79728 6.19931L12.6132 8.26692L15.508 11.5752H19.2297' stroke='#ffffff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/><path d='M8.89152 15.7103L7.65095 16.5374H4.34277' stroke='#ffffff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/></svg>" },
{ title: "Downloader", description: "You wouldnt download a car - welp i would :D u can download videos from poke for 0$!", icon: "<svg style='background: #519355;' width='24px' height='24px' stroke-width='1.5' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg' color='#ffffff'><path d='M12 8V16M12 16L15.5 12.5M12 16L8.5 12.5' stroke='#ffffff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/><path d='M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z' stroke='#ffffff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/></svg>" },
{ title: "DRM Free", description: "Poke comes without digital restrictions management - poke is free software :3", icon: "<svg style='background: #b7a358;' width='24px' height='24px' stroke-width='1.5' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg' color='#ffffff'><path d='M4.62323 5.24841C2.99408 7.02743 2 9.39765 2 12C2 17.5229 6.47715 22 12 22C14.5361 22 16.8517 21.0559 18.6146 19.5' stroke='#ffffff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/><path d='M21.3021 15.6775C21.7525 14.5392 22 13.2985 22 12C22 6.47715 17.5228 2 12 2C10.7687 2 9.58934 2.22255 8.5 2.62961' stroke='#ffffff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/><path d='M9 15C9.64448 15.8593 10.8428 16.3494 12 16.391C13.1141 16.431 14.1901 16.0554 14.6973 15.1933' stroke='#ffffff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/><path d='M12 16.391V18.5' stroke='#ffffff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/><path d='M9.5 9.5C9.5 10.6811 10.3525 11.1647 11.3862 11.5' stroke='#ffffff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/><path d='M15 8.5C14.315 7.81501 13.1087 7.33855 12 7.30872V5.5' stroke='#ffffff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/><path d='M3 3L21 21' stroke='#ffffff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/></svg>" },
{ title: "Games Included", description: "U can play funnie games on poke!", icon: "<svg style='background: #886dea;' width='24px' height='24px' viewBox='0 0 24 24' stroke-width='1.5' fill='none' xmlns='http://www.w3.org/2000/svg' color='#ffffff'><path d='M17.5 17.5C20 21 23.9486 18.4151 23 15C21.5753 9.87113 20.8001 7.01556 20.3969 5.50793C20.1597 4.62136 19.3562 4 18.4384 4L5.56155 4C4.64382 4 3.844 4.62481 3.62085 5.515C2.7815 8.86349 2.0326 11.8016 1.14415 15C0.195501 18.4151 4.14415 21 6.64415 17.5' stroke='#ffffff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/><path d='M16 4V6C16 7.10457 15.1046 8 14 8H10C8.89543 8 8 7.10457 8 6L8 4' stroke='#ffffff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/><path d='M8 16C9.10457 16 10 15.1046 10 14C10 12.8954 9.10457 12 8 12C6.89543 12 6 12.8954 6 14C6 15.1046 6.89543 16 8 16Z' stroke='#ffffff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/><path d='M16 16C17.1046 16 18 15.1046 18 14C18 12.8954 17.1046 12 16 12C14.8954 12 14 12.8954 14 14C14 15.1046 14.8954 16 16 16Z' stroke='#ffffff' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/></svg>" }
@ -188,9 +191,6 @@ const randomFeatures = features.sort(() => 0.5 - Math.random()).slice(0, 3);
secondary_text='Discord',
secondary_link='https://discord.poketube.fun',
primary_icon='<svg version="1.1" viewBox="0 0 27.9 32" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><g transform="translate(-.095 .005)" fill="#040404"><path d="m27.1 31.2v-30.5h-2.19v-0.732h3.04v32h-3.04v-0.732z"/><path d="m8.23 10.4v1.54h0.044c0.385-0.564 0.893-1.03 1.49-1.37 0.58-0.323 1.25-0.485 1.99-0.485 0.72 0 1.38 0.14 1.97 0.42 0.595 0.279 1.05 0.771 1.36 1.48 0.338-0.5 0.796-0.941 1.38-1.32 0.58-0.383 1.27-0.574 2.06-0.574 0.602 0 1.16 0.074 1.67 0.22 0.514 0.148 0.954 0.383 .32 0.707 0.366 0.323 0.653 0.746 0.859 1.27 0.205 0.522 0.308 1.15 0.308 1.89v7.63h-3.13v-6.46c0-0.383-0.015-0.743-0.044-1.08-0.0209-0.307-0.103-0.607-0.242-0.882-0.133-0.251-0.336-0.458-0.584-0.596-0.257-0.146-0.606-0.22-1.05-0.22-0.44 0-0.796 0.085-1.07 0.253-0.272 0.17-0.485 0.39-0.639 0.662-0.159 0.287-0.264 0.602-0.308 0.927-0.052 0.347-0.078 0.697-0.078 1.05v6.35h-3.13v-6.4c0-0.338-7e-3 -0.673-0.021-1-0.0114-0.314-0.0749-0.623-0.188-0.916-0.108-0.277-0.3-0.512-0.55-0.673-0.258-0.168-0.636-0.253-1.14-0.253-0.198 0.0083-0.394 0.042-0.584 0.1-0.258 0.0745-0.498 0.202-0.705 0.374-0.228 0.184-0.422 0.449-0.584 0.794-0.161 0.346-0.242 0.798-0.242 1.36v6.62h-3.13v-11.4z"/><path d="m0.936 0.732v30.5h2.19v0.732h-3.04v-32h3.03v0.732z"/></g></svg>',
primary_text='Matrix',
primary_link='https://matrix.to/#/%23poke:vern.cc'
)%>
<%- include('./partials/card',

View File

@ -1,13 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Poke - <%=error%> !!!</title>
<head>
<title>Poke - <%= error %> !!!</title>
<meta content="#111111" name="theme-color" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no, viewport-fit=cover" />
<meta name="darkreader-lock" />
<% if (description == "This helps protect our community. Learn more (TRYING AGAIN....)") { %>
<meta http-equiv="refresh" content="5">
<% } %>
<link href="/css/yt-ukraine.svg?v=3" rel="icon" />
<link rel="manifest" href="/manifest.json" />
<style>
@ -81,29 +78,69 @@
.error-footer a:hover {
color: #d69cc8;
}
.countdown {
margin-top: 16px;
color: #ccc;
font-size: 14px;
}
</style>
</head>
<body>
<% if (description == "This helps protect our community. Learn more (TRYING AGAIN....)") { %>
<% const RESTART_MSG = "Poke is currently restarting - please wait 1-2 minutes.."; %>
<% if (description === RESTART_MSG) { %>
<script>
// Client-side reload logic
let reloadCount = parseInt(localStorage.getItem('reloadCount') || '0', 10);
reloadCount++;
localStorage.setItem('reloadCount', reloadCount);
let seconds = reloadCount > 5 ? 30 : 10;
function updateCountdown() {
const el = document.getElementById('countdown');
if (el) {
if (reloadCount > 5) {
document.querySelector('.error p').textContent = "This is taking so long...";
}
el.textContent = "Trying again in " + seconds + " seconds...";
}
if (seconds <= 0) {
location.reload();
} else {
seconds--;
setTimeout(updateCountdown, 1000);
}
}
window.addEventListener('DOMContentLoaded', updateCountdown);
</script>
<% } else { %>
<script>
// Clear reload count on non-restart errors
localStorage.removeItem('reloadCount');
</script>
<% } %>
</head>
<body>
<% if (description === RESTART_MSG) { %>
<p id="abstract">502</p>
<% } else if (description !== "This helps protect our community. Learn more (TRYING AGAIN....)") { %>
<% } else { %>
<p id="abstract">404</p>
<% } %>
<div class="error">
<h2><%=error%></h2>
<p><%=description%></p>
<h2><%= error %></h2>
<p><%= description %></p>
<% if (description === RESTART_MSG) { %>
<div class="countdown" id="countdown"></div>
<% } %>
</div>
<div class="error-footer">
<a href="https://codeberg.org/ashley/poke/issues/new/choose">Create issue</a>
<a href="https://discord.poketube.fun">Report on our Discord</a>
<% if (description == "This helps protect our community. Learn more (TRYING AGAIN....)") { %>
<% if (description === RESTART_MSG) { %>
<a href="https://github.com/iv-org/invidious/issues">See Invidious issues</a>
<a href="">Refresh Page</a>
<% } %>
</div>
</body>
</body>
</html>

View File

@ -22,7 +22,7 @@
* @licstart The following is the entire license notice for the JavaScript
* code in this page.
*
* Copyright (C) 2021-2023 POKETUBE (https://github.com/iamashley0/poketube)
* Copyright (C) 2021-2025 POKETUBE (https://github.com/iamashley0/poketube)
*
* The JavaScript code in this page is free software: you can redistribute
* it and/or modify it under the terms of the GNU General Public License
@ -44,6 +44,178 @@
//--><!]]>
</script>
<script src="/static/maps.js"></script><script src="/static/data-mobile.js"></script>
<script>(function(){
const _0x5a3c=[
"P2Jib3g9LTE2NS43NjE3MTg3NTAwMDAwMyUyQy0zLjg2NDI1NDYxNTcyMTM5NiUyQzMwLjQxMDE1NjI1MDAwMDAwNCUyQzcyLjQ0ODc5MTU1NzMwNjcyJmxheWVyPW1hcG5paw==",
"aHR0cHM6Ly93d3cub3BlbnN0cmVldG1hcC5vcmcvZXhwb3J0L2VtYmVkLmh0bWw=",
"d3d3Lm9wZW5zdHJlZXRtYXAub3Jn"
];
function _0x99f2(i){ return atob(_0x5a3c[i]); }
function updateMap(lat, lon) {
const delta = 0.25;
const bbox = `?bbox=${lon-delta},${lat-delta},${lon+delta},${lat+delta}&layer=mapnik`;
const newURL = _0x99f2(1) + bbox;
const iframe = document.querySelector('iframe');
if (iframe) {
iframe.src = newURL;
window.history.pushState({}, '', newURL);
}
const marker = document.getElementById('map-marker');
if (marker) marker.remove();
const newMarker = document.createElement('div');
newMarker.id = 'map-marker';
newMarker.style = 'position:absolute;width:20px;height:20px;background:red;border-radius:50%;transform:translate(-50%,-50%);z-index:9998;pointer-events:none;left:50%;top:50%';
document.body.appendChild(newMarker);
}
function copyCoordinates() {
const marker = document.getElementById('map-marker');
if (!marker) return alert('No coordinates to copy.');
navigator.clipboard.writeText(window.location.href).then(() => {
alert('Current map link copied to clipboard!');
});
}
function locateAndUpdate() {
if (!navigator.geolocation) {
alert('Geolocation is not supported by your browser.');
return;
}
navigator.geolocation.getCurrentPosition(
pos => {
updateMap(pos.coords.latitude, pos.coords.longitude);
},
err => {
alert('Unable to retrieve location: ' + err.message);
},
{ enableHighAccuracy: true, timeout: 10000, maximumAge: 0 }
);
}
function _0x4f2a(){
const bbox = _0x99f2(0);
const base = _0x99f2(1);
const url = base + bbox;
const iframe = document.querySelector('iframe');
if (!iframe) return setTimeout(_0x4f2a, 100);
iframe.src = url;
iframe.addEventListener('load',()=>{
try {
const doc = iframe.contentDocument || iframe.contentWindow.document;
Array.from(doc.querySelectorAll('a')).forEach(a=>a.addEventListener('click',_linkHandler));
Array.from(doc.querySelectorAll('*')).forEach(el=>{
const bg = el.style.backgroundImage;
if(bg.includes('//dka575ofm4ao0.cloudfront.net')){
el.style.backgroundImage = bg.replace(/\/\/dka575ofm4ao0\.cloudfront\.net/g,
m=>`https://p.poketube.fun/https://dka575ofm4ao0.cloudfront.net`);
}
});
} catch(e) {
console.warn('Cross-origin access denied, skipping DOM manipulation.');
}
});
window.history = new Proxy(window.history,{
get(target, prop){
if(prop === 'pushState') return (...args)=>{
const iframe = document.querySelector('iframe');
if(iframe && args[2]) iframe.src = args[2];
return target.pushState.apply(target, args);
};
return Reflect.get(target, prop);
}
});
window.addEventListener('popstate',()=>{
const iframe = document.querySelector('iframe');
if (iframe) iframe.src = location.href;
});
}
function _linkHandler(e){
const h = e.target.href;
const iframe = document.querySelector('iframe');
if(!iframe) return;
if(h.includes(_0x99f2(2))){
e.preventDefault();
iframe.src = h;
window.history.pushState({}, '', h);
} else {
window.location.href = h;
}
}
const form = document.createElement('form');
form.style = 'position:absolute;top:10px;right:10px;z-index:9999;background:rgba(0,0,0,0.5);backdrop-filter:blur(12px);padding:10px 12px;border-radius:12px;box-shadow:0 4px 10px rgba(0,0,0,0.4);font-family:sans-serif;min-width:220px;';
form.innerHTML = `
<input id="searchBox" type="text" placeholder="Search..." style="padding:6px 10px;width:180px;font-size:14px;border:1px solid #444;border-radius:6px;background:#222;color:#fff">
<ul id="suggestions" style="list-style:none;margin:6px 0 0;padding:0;max-height:180px;overflow:auto;background:#111;border:1px solid #333;border-radius:6px;display:none;position:relative;z-index:10000;color:#fff;"></ul>
<div style="margin-top:10px;display:flex;gap:6px;flex-wrap:wrap">
<button id="locate-btn" type="button" style="flex:1;padding:4px 6px;font-size:12px;background:#333;color:#fff;border:none;border-radius:6px">📍 Locate</button>
<button type="button" style="flex:1;padding:4px 6px;font-size:12px;background:#333;color:#fff;border:none;border-radius:6px" onclick="copyCoordinates()">📋 Copy</button>
<button type="button" style="flex:1;padding:4px 6px;font-size:12px;background:#333;color:#fff;border:none;border-radius:6px" onclick="location.reload()">🔁 Reset</button>
</div>
`;
document.body.appendChild(form);
document.getElementById('locate-btn').addEventListener('click', locateAndUpdate);
const input = form.querySelector('#searchBox');
const suggestions = form.querySelector('#suggestions');
input.addEventListener('input', () => {
const query = input.value.trim();
if (!query) return suggestions.style.display = 'none';
fetch(`https://nominatim.openstreetmap.org/search?q=${encodeURIComponent(query)}&format=json&limit=5`)
.then(res => res.json())
.then(data => {
suggestions.innerHTML = '';
data.forEach(place => {
const li = document.createElement('li');
li.textContent = place.display_name;
li.style = 'padding:6px 10px;cursor:pointer;border-bottom:1px solid #222;font-size:13px;background:#111';
li.addEventListener('click', () => {
input.value = place.display_name;
suggestions.style.display = 'none';
updateMap(parseFloat(place.lat), parseFloat(place.lon));
});
suggestions.appendChild(li);
});
suggestions.style.display = 'block';
});
});
form.addEventListener('submit', e => {
e.preventDefault();
const q = input.value.trim();
if(!q) return;
fetch(`https://nominatim.openstreetmap.org/search?q=${encodeURIComponent(q)}&format=json&limit=1`)
.then(res => res.json())
.then(data => {
if(data[0]){
updateMap(parseFloat(data[0].lat), parseFloat(data[0].lon));
}
});
});
const fab = document.createElement('button');
fab.textContent = '+';
fab.style = 'position:fixed;bottom:20px;right:20px;width:48px;height:48px;font-size:24px;background:#111;color:#fff;border:none;border-radius:50%;box-shadow:0 2px 10px rgba(0,0,0,0.4);cursor:pointer;z-index:9999';
fab.title = 'More Tools';
fab.onclick = () => alert('More features coming soon!');
document.body.appendChild(fab);
const branding = document.createElement('div');
branding.textContent = 'PokeMaps';
branding.style = 'position: absolute; bottom: 10px; left: 10px; padding: 6px 10px; font-size: 31px; font-weight: 500; background: rgba(0, 0, 0, 0.6); color: white; border-radius: 6px; font-family: sans-serif; backdrop-filter: blur(6px); z-index: 9999; pointer-events: none;display: block;';
document.body.appendChild(branding);
_0x4f2a();
})();
</script><script src="/static/data-mobile.js"></script>
</body>
</html>

View File

@ -11,7 +11,6 @@
<% if (has_secondary_action=="true") { %>
<a class="card-secondary" href="<%= secondary_link %>"><%- secondary_icon %> <%= secondary_text %></a>
<% } %>
<a class="card-primary" href="<%= primary_link %>"><%- primary_icon %> <%= primary_text %></a>
</div>
<% }%>
</div>

View File

@ -424,7 +424,10 @@ video[counter].classList.add("shake");
</div> </div>
<div class=right>
<div class=right style="background: #333;
border-radius: 2em;
height: 49px;
margin-top: 5px;">
<button title="Play/Pause Ambient music" class="a" id="audioButton" onclick="toggleAudio()">
<i id="audioIcon" class="fas fa-pause"></i>
@ -452,7 +455,7 @@ video[counter].classList.add("shake");
<div id="filters-box"><form action="/search" method="get">
<input type="hidden" name="query" value="<%- q %>">
<input type="hidden" name="continuation" value="<%- continuation %>">
<div id="filters-flex" style="display: flex;gap: 18px;background: #111;border-radius: 1em;padding: 6px;width: fit-content;margin-left: auto;margin-right: auto;"> <div class="filter-column"><fieldset>
<div id="filters-flex" style="display: flex;gap: 18px;background: #111;border-radius: 1em;margin-top: 6px;padding: 6px;width: fit-content;margin-left: auto;margin-right: auto;"> <div class="filter-column"><fieldset>
<legend><div class="filter-name underlined">Upload date</div></legend>
<div class="filter-options">
<% const selectedDate = date || "none"; %>
@ -494,7 +497,8 @@ video[counter].classList.add("shake");
<% }) %>
</div> </fieldset></div>
<br> <div id="filters-apply"> <button type="submit" style="color:#fff;background:#333;padding:3px;border-radius:11px;margin-top: 6em;">Apply!</button></div>
<br> <div id="filters-apply">
<button type="submit" style="color:#fff;background:#333;padding:6px;border-radius:9px;margin-top: 6em;border: 1px solid gray;">Apply!</button></div>
</div>
</form></div> </details></div>
@ -511,23 +515,22 @@ Web </a>
</div>
</div>
<%
const query = q.toLowerCase().trim();
let answer = '';
function isMathExpression(query) {
return /^[0-9\s\+\-\*\/\.\x]+$/.test(query);
}
function evaluateMathExpression(expression) {
// twenyone
if (expression.replace(/\s+/g, '') === '9+10') {
return '21';
if (/^[0-9\s+\-*/.x]+$/.test(query)) {
const expr = query.replace(/\s+/g, '');
answer = expr === '9+10' ? '21' : (() => {
try { return eval(expr); } catch { return 'Invalid Expression'; }
})();
return answer;
}
try {
return eval(expression);
} catch (error) {
return 'Invalid Expression';
}
}
function getCurrentDate() {
const now = new Date();
return now.toLocaleDateString();
@ -538,7 +541,7 @@ function getCurrentYear() {
}
function getTimeInTimezone(location) {
const timezones = {
const tzMap = {
"california": "America/Los_Angeles",
"new york": "America/New_York",
"chicago": "America/Chicago",
@ -568,9 +571,7 @@ function getTimeInTimezone(location) {
"jakarta": "Asia/Jakarta",
"delhi": "Asia/Kolkata",
"mumbai": "Asia/Kolkata",
"kolkata": "Asia/Kolkata",
"karachi": "Asia/Karachi",
"lahore": "Asia/Karachi",
"dubai": "Asia/Dubai",
"abu dhabi": "Asia/Dubai",
"riyadh": "Asia/Riyadh",
@ -586,10 +587,92 @@ function getTimeInTimezone(location) {
"vienna": "Europe/Vienna",
"stockholm": "Europe/Stockholm",
"oslo": "Europe/Oslo",
"helsinki": "Europe/Helsinki"
};
"helsinki": "Europe/Helsinki",
"prague": "Europe/Prague",
"budapest": "Europe/Budapest",
"warsaw": "Europe/Warsaw",
"bucharest": "Europe/Bucharest",
"sofia": "Europe/Sofia",
"zagreb": "Europe/Zagreb",
"belgrade": "Europe/Belgrade",
"sarajevo": "Europe/Sarajevo",
"podgorica": "Europe/Podgorica",
"ljubljana": "Europe/Ljubljana",
"tirana": "Europe/Tirane",
"valletta": "Europe/Malta",
"andorra la vella": "Europe/Andorra",
"monaco": "Europe/Monaco",
"luxembourg": "Europe/Luxembourg",
"bratislava": "Europe/Bratislava",
"vilnius": "Europe/Vilnius",
"riga": "Europe/Riga",
"tallinn": "Europe/Tallinn",
"istanbul": "Europe/Istanbul",
"jerusalem": "Asia/Jerusalem",
"amman": "Asia/Amman",
"beirut": "Asia/Beirut",
"damascus": "Asia/Damascus",
"baghdad": "Asia/Baghdad",
"tehran": "Asia/Tehran",
"islamabad": "Asia/Karachi",
"kathmandu": "Asia/Kathmandu",
"thimphu": "Asia/Thimphu",
"dhaka": "Asia/Dhaka",
"yangon": "Asia/Yangon",
"hanoi": "Asia/Ho_Chi_Minh",
"ho chi minh city": "Asia/Ho_Chi_Minh",
"manila": "Asia/Manila",
"singapore": "Asia/Singapore",
"kuala lumpur": "Asia/Kuala_Lumpur",
"colombo": "Asia/Colombo",
"bagotville": "America/Montreal",
"toronto": "America/Toronto",
"vancouver": "America/Vancouver",
"mexico city": "America/Mexico_City",
"guadalajara": "America/Mexico_City",
"monterrey": "America/Monterrey",
"sao paulo": "America/Sao_Paulo",
"buenos aires": "America/Argentina/Buenos_Aires",
"santiago": "America/Santiago",
"rio de janeiro": "America/Sao_Paulo",
"caracas": "America/Caracas",
"bogota": "America/Bogota",
"lima": "America/Lima",
"quito": "America/Quito",
"georgetown": "America/Guyana",
"paramaribo": "America/Paramaribo",
"cayenne": "America/Cayenne",
"kingston": "America/Jamaica",
"port_of_spain": "America/Port_of_Spain",
"st johns": "America/St_Johns",
"midway": "Pacific/Midway",
"apia": "Pacific/Apia",
"nuku alofa": "Pacific/Tongatapu",
"tarawa": "Pacific/Tarawa",
"funafuti": "Pacific/Funafuti",
"suva": "Pacific/Fiji",
"chatham": "Pacific/Chatham",
"pitcairn": "Pacific/Pitcairn",
"galapagos": "Pacific/Galapagos",
"easter island": "Pacific/Easter",
"honiara": "Pacific/Guadalcanal",
"port vila": "Pacific/Efate",
"palikir": "Pacific/Pohnpei",
"palau": "Pacific/Palau",
"mcmurdo": "Antarctica/McMurdo",
"rothera": "Antarctica/Rothera",
"troll": "Antarctica/Troll",
"davis": "Antarctica/Davis",
"casey": "Antarctica/Casey",
"mawson": "Antarctica/Mawson",
"vostok": "Antarctica/Vostok",
"syowa": "Antarctica/Syowa",
"gmt": "Etc/GMT",
"utc": "UTC"
};
const timezone = timezones[location.toLowerCase()];
const timezone = tzMap[location.toLowerCase()];
if (!timezone) {
return null;
}
@ -599,9 +682,186 @@ function getTimeInTimezone(location) {
return now.toLocaleTimeString('en-US', options);
}
const query = q.toLowerCase().trim();
let answer = '';
function randomCompliment() {
const compliments = [
"Youre an awesome friend.",
"You light up the room.",
"You have a great sense of humor.",
"You make a difference.",
"You're like a ray of sunshine."
];
return compliments[Math.floor(Math.random() * compliments.length)];
}
function randomEncouragement() {
const encourages = [
"Keep going—youve got this!",
"Dont give up now!",
"Every step counts.",
"Believe in yourself.",
"You can do anything."
];
return encourages[Math.floor(Math.random() * encourages.length)];
}
function base64Encode(str) {
return btoa(str);
}
function base64Decode(str) {
try {
return atob(str);
} catch {
return 'Invalid Base64';
}
}
function hexToDec(str) {
return parseInt(str.replace(/^0x/, ''), 16).toString();
}
function decToHex(num) {
return Number(num).toString(16);
}
function textToCharCodes(text) {
return text.split('').map(c => c.charCodeAt(0)).join(' ');
}
function charCodesToText(codes) {
return String.fromCharCode(...codes.split(/\s+/).map(n => +n));
}
function countWords(text) {
return text.trim().split(/\s+/).length;
}
function titleCase(text) {
return text
.split(' ')
.map(w => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())
.join(' ');
}
function slugify(text) {
return text
.toLowerCase()
.trim()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-+|-+$/g, '');
}
function isPrime(n) {
n = Number(n);
if (n < 2) return false;
for (let i = 2; i <= Math.sqrt(n); i++) {
if (n % i === 0) return false;
}
return true;
}
function gcd(a, b) {
a = Math.abs(a); b = Math.abs(b);
while (b) [a, b] = [b, a % b];
return a;
}
function lcm(a, b) {
return Math.abs(a * b) / gcd(a, b);
}
function fibonacci(n) {
n = Number(n);
if (n < 2) return n;
let a = 0, b = 1;
for (let i = 2; i <= n; i++) [a, b] = [b, a + b];
return b;
}
function generatePassword(length = 8) {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()';
let pw = '';
for (let i = 0; i < length; i++) {
pw += chars.charAt(Math.floor(Math.random() * chars.length));
}
return pw;
}
function daysUntil(dateStr) {
const now = new Date();
const then = new Date(dateStr);
const diff = then - now;
return diff > 0
? Math.ceil(diff / (1000 * 60 * 60 * 24)) + ' days'
: 'Date passed';
}
function generateUUID() {
return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(
/[018]/g,
c => (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
);
}
function generateRandomString(length = 8) {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let s = '';
for (let i = 0; i < length; i++) {
s += chars.charAt(Math.floor(Math.random() * chars.length));
}
return s;
}
const emojiMap = {
"grinning face":"😀","grin":"😁","smiley":"😃","smile":"😄","sweat smile":"😅",
"joy":"😂","rofl":"🤣","relaxed":"☺️","blush":"😊","innocent":"😇",
"slightly_smiling_face":"🙂","upside_down":"🙃","wink":"😉","relieved":"😌",
"heart eyes":"😍","kissing_heart":"😘","kissing":"😗","kissing_smiling_eyes":"😙",
"kissing_closed_eyes":"😚","yum":"😋","stuck out tongue":"😛","stuck out tongue wink":"😜",
"stuck out tongue closed eyes":"😝","money_mouth":"🤑","hug":"🤗","nerd":"🤓",
"sunglasses":"😎","star_struck":"🤩","thinking":"🤔","zipper_mouth":"🤐",
"raised_eyebrow":"🤨","neutral":"😐","expressionless":"😑","no_mouth":"😶",
"roll_eyes":"🙄","smirk":"😏","persevere":"😣","disappointed_relieved":"😥",
"cold_sweat":"😰","pensive":"😔","confused":"😕","worried":"😟","slightly_frowning":"🙁",
"frowning":"☹️","anguished":"😧","open_mouth":"😮","grimacing":"😬","hushed":"😯",
"astonished":"😲","flushed":"😳","pleading":"🥺","frowning2":"😦","anguished2":"😧",
"cry":"😢","disappointed":"😞","scream":"😱","fearful":"😨","tired_face":"😫",
"weary":"😩","triumph":"😤","angry":"😠","rage":"😡","poop":"💩","thumbsup":"👍",
"thumbsdown":"👎","clap":"👏","raised_hands":"🙌","pray":"🙏","muscle":"💪","eyes":"👀",
"ear":"👂","nose":"👃","tongue":"👅","lips":"👄","kiss":"💋","crown":"👑","womans hat":"👒",
"eyeglasses":"👓","necktie":"👔","shirt":"👕","jeans":"👖","dress":"👗","kimono":"👘",
"bikini":"👙","sandal":"👡","boot":"👢","mans shoe":"👞","high heel":"👠","sock":"🧦",
"gloves":"🧤","scarf":"🧣","tophat":"🎩","billed cap":"🧢","flag us":"🇺🇸","flag gb":"🇬🇧",
"flag ca":"🇨🇦","flag de":"🇩🇪","flag fr":"🇫🇷","flag es":"🇪🇸","flag it":"🇮🇹","flag jp":"🇯🇵",
"flag cn":"🇨🇳","flag in":"🇮🇳","flag br":"🇧🇷","flag ru":"🇷🇺","flag za":"🇿🇦","flag au":"🇦🇺",
"flag nz":"🇳🇿","flag ng":"🇳🇬","flag eg":"🇪🇬","flag ar":"🇦🇷","flag mx":"🇲🇽","flag kr":"🇰🇷",
"flag tr":"🇹🇷",
// animals
"dog face":"🐶","cat face":"🐱","mouse face":"🐭","hamster":"🐹","rabbit":"🐰",
"fox face":"🦊","bear face":"🐻","koala":"🐨","tiger face":"🐯","lion face":"🦁",
"cow face":"🐮","pig face":"🐷","frog face":"🐸","octopus":"🐙","monkey face":"🐵",
"chicken":"🐔","penguin":"🐧","bird":"🐦","baby chick":"🐤","hatching chick":"🐣",
// nature
"sun":"☀️","moon":"🌙","star":"⭐️","cloud":"☁️","umbrella":"☂️","snowflake":"❄️",
"fire":"🔥","droplet":"💧","ocean":"🌊","volcano":"🌋","cactus":"🌵","palm tree":"🌴",
"evergreen tree":"🌲","deciduous tree":"🌳","fallen leaf":"🍂","maple leaf":"🍁",
"seedling":"🌱","flower":"🌸","rose":"🌹","sunflower":"🌻","blossom":"🌼",
//food
"grapes":"🍇","watermelon":"🍉","tangerine":"🍊","banana":"🍌","pineapple":"🍍",
"apple":"🍎","pear":"🍐","peach":"🍑","strawberry":"🍓","cherries":"🍒","mango":"🥭",
"lemon":"🍋","coffee":"☕️","tea":"🍵","beer":"🍺","wine glass":"🍷","cocktail":"🍸",
"tropical drink":"🍹","birthday cake":"🎂","pizza":"🍕","hamburger":"🍔","fries":"🍟",
"hot dog":"🌭","taco":"🌮","burrito":"🌯","popcorn":"🍿","chocolate bar":"🍫",
"candy":"🍬","lollipop":"🍭","honey pot":"🍯"
};
let m;
if (isMathExpression(query)) {
answer = evaluateMathExpression(query);
} else if (query.includes('date') || query.includes('what date is it')) {
@ -618,17 +878,70 @@ if (isMathExpression(query)) {
const options = { weekday: 'long' };
answer = now.toLocaleDateString(undefined, options);
} else if (query.includes('u are cute') || query.includes('you are cute')) {
answer = "jifshfgdhjf >~< no u"
answer = "jifshfgdhjf >~< no u";
} else if (query.includes('ur cute') || query.includes('your cute')) {
answer = "efkohgefgef >///< no u"
answer = "efkohgefgef >///< no u";
} else if (query.includes('am i cute') || query.includes('am i a cutie?')) {
answer = "yesh :3 u are "
answer = "yesh :3 u are ";
} else if (query.includes('am i a good girl') || query.includes('am i a good boy?')) {
answer = query.includes('girl') ? "yesh :3 u are a good girl" : "yesh :3 u are a good boy";
answer = query.includes('girl')
? "yesh :3 u are a good girl"
: "yesh :3 u are a good boy";
} else if (query.includes('ur hot') || query.includes('you are hot')) {
answer = "jrifyehgyerfgu9wdswgfsafgydwgbfwdfge >~< "
answer = "jrifyehgyerfgu9wdswgfsafgydwgbfwdfge >~< ";
} else if (/^(?:emoji\s+(.+)|(.+)\s+emoji)$/.test(query)) {
const match = query.match(/^(?:emoji\s+(.+)|(.+)\s+emoji)$/);
let name = (match[1] || match[2]).trim().toLowerCase();
const keySpace = name.replace(/_/g, ' ');
const keyUnderscore = name.replace(/\s+/g, '_');
answer = emojiMap[keySpace]
|| emojiMap[keyUnderscore]
|| 'Unknown emoji';
} else if (query.includes('compliment')) {
answer = randomCompliment();
} else if (query.includes('encouragement') || query.includes('encourage me')) {
answer = randomEncouragement();
} else if (query.startsWith('base64 encode ')) {
answer = base64Encode(query.slice(14));
} else if (query.startsWith('base64 decode ')) {
answer = base64Decode(query.slice(14));
} else if ((m = /0x[0-9a-f]+/i.exec(query))) {
answer = hexToDec(m[0]);
} else if (query.match(/\d+\s+to\s+hex/i)) {
answer = decToHex(query.match(/\d+/)[0]);
} else if (query.startsWith('char codes for ')) {
answer = textToCharCodes(query.slice(15));
} else if (query.startsWith('text from codes ')) {
answer = charCodesToText(query.slice(16));
} else if (query.startsWith('word count of ')) {
answer = countWords(query.slice(14)).toString();
} else if (query.startsWith('titlecase ')) {
answer = titleCase(query.slice(10));
} else if (query.startsWith('slugify ')) {
answer = slugify(query.slice(8));
} else if (query.match(/\bprime\b/)) {
answer = isPrime(query.match(/\d+/)[0]) ? 'Yes' : 'No';
} else if (query.includes('gcd of ')) {
const nums = query.match(/\d+/g);
answer = gcd(nums[0], nums[1]).toString();
} else if (query.includes('lcm of ')) {
const nums = query.match(/\d+/g);
answer = lcm(nums[0], nums[1]).toString();
} else if (query.match(/fib(?:onacci)?\s*\d+/i)) {
answer = fibonacci(query.match(/\d+/)[0]).toString();
} else if (query.startsWith('generate password')) {
const n = query.match(/\d+/);
answer = generatePassword(n ? Number(n[0]) : undefined);
} else if (query.includes('days until ')) {
answer = daysUntil(query.split('days until ')[1].trim());
} else if (query.includes('uuid')) {
answer = generateUUID();
} else if (query.startsWith('random string')) {
const n = query.match(/\d+/);
answer = generateRandomString(n ? Number(n[0]) : undefined);
}
const upsellMessages = [
"[new] Try searching 'What's 4+4?'",
"[new] Ask 'What's the date today?'",
@ -653,32 +966,111 @@ function extractQueryFromUpsellMessage(message) {
%>
%>
<% if (answer) { %>
<div class="container">
<h2 style="font-family: 'PokeTube Flex';font-size: large;text-align: left !important;font-stretch: ultra-expanded; font-weight: 1000; margin-bottom: -0.1em;">
<div class="container" style="padding: 1em;">
<h2 style="font-family: 'PokeTube Flex'; font-size: large; text-align: left !important; font-stretch: ultra-expanded; font-weight: 1000; margin-bottom: -0.1em;">
Answer to ur question
</h2>
<h2 style="font-family: 'PokeTube Flex';font-size: large;text-align: right !important;font-stretch: ultra-expanded; font-weight: 1000; margin-bottom: -0.1em;margin-top: -1em;"><i title="PokeInstant Anwser! (not ai/LLM)" class="fa-light fa-sparkles"></i></h2>
<span style="font-size: 7em; margin-bottom: 3em; text-align: left !important; margin-right: 7em;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;"><%= answer %></span>
</div>
<% } else if (showUpsell) { %>
<% } %>
<% if (q == "ai" || q == "aibot" || q == "chatbot") { %>
<div class="container">
<h2 style="font-family: 'PokeTube Flex'; font-size: large; text-align: center !important; font-stretch: ultra-expanded; font-weight: 1000; margin-bottom: -0.1em;">
No, POKE Will Never Have "AI" —Because It Doesn't Need It
<h2 style="font-family: 'PokeTube Flex'; font-size: large; text-align: right !important; font-stretch: ultra-expanded; font-weight: 1000; margin-bottom: -0.1em; margin-top: -1em;">
<i title="PokeIntellagance!" class="fa-light fa-sparkles"></i>
</h2>
<span style="margin-bottom: 3em; text-align: left !important; margin-right: 7em; white-space: pre-wrap; word-break: break-word;">
POKE doesnt need "AI." Theres no good reason for a YouTube front end to include some gimmicky AI assistant. These days, "AI" just means slapping a ChatGPT wrapper on an app, calling it innovative, and hoping no one notices the lack of actual purpose. Its the latest fad, sure, but POKE is about simplicity, privacy, and doing things right—not just joining tech trends for the sake of it.
<br>
POKE is here to make watching videos smoother, not cluttered with unnecessary "features." Real value doesnt come from chasing whatever big tech wants to sell you on. Its about staying true to what actually helps users. So, yeah, no AI here, and honestly, no need for it.
<br>
If u really want a "chatbot" or "ai" : <a href="https://chatgpt.com/"> look at the chatgpt website </a> - (or search using the !ai bang - which is made by duckduckgo, not <a href="https://duckduckgo.com/duckduckgo-help-pages/features/bangs/">us</a>)
</span>
<span
id="answer-text"
style="
display: block;
font-size: 7em;
white-space: pre-wrap;
word-break: break-word;
"
><%= answer %></span>
<div style="display: flex; gap: 1em;">
<button
id="copy-btn"
style="
font-size: 1em;
padding: 0.5em 1em;
cursor: pointer;
background: #222;
color: #fff;
border: none;
border-radius: 0.25em;
"
>Copy</button>
<button
id="ask-btn"
style="font-size:1em; padding:0.5em 1em;"
>Ask ChatGPT</button>
</div>
</div>
<noscript>
<style>
#copy-btn,
#ask-btn {
display: none !important;
}
</style>
</noscript>
<style>
/* Rainbow border keyframes */
@keyframes rainbow-border {
0% { border-color: red; }
16% { border-color: orange; }
32% { border-color: yellow; }
48% { border-color: green; }
64% { border-color: blue; }
80% { border-color: indigo; }
100% { border-color: violet; }
}
#ask-btn {
background: linear-gradient(45deg, #6a11cb, #2575fc);
color: #fff;
border: 2px solid transparent; /* base border */
border-radius: 0.5em;
padding: 0.6em 1.2em;
cursor: pointer;
box-shadow: 0 4px 15px rgba(0,0,0,0.2);
transition: transform 0.1s ease, box-shadow 0.2s ease;
}
#ask-btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(0,0,0,0.3);
animation: rainbow-border 2s linear infinite; /* apply rainbow */
}
#ask-btn:active {
transform: translateY(0);
box-shadow: 0 3px 10px rgba(0,0,0,0.2);
}
</style>
<script>
;(function() {
const copyBtn = document.getElementById('copy-btn');
const askBtn = document.getElementById('ask-btn');
const textEl = document.getElementById('answer-text');
copyBtn.addEventListener('click', () => {
const text = textEl.innerText || textEl.textContent;
navigator.clipboard.writeText(text).then(() => {
copyBtn.textContent = 'Copied!';
setTimeout(() => { copyBtn.textContent = 'Copy'; }, 1500);
});
});
askBtn.addEventListener('click', () => {
const userQuery = prompt('What would you like to ask ChatGPT?');
if (userQuery) {
window.location.href = `https://chatgpt.com/?q=${encodeURIComponent(userQuery)}`;
}
});
})();
</script>
<% } else if (showUpsell) { %>
<% } %>
<!-- self harm -->
<%
const searchStrings = [
@ -1018,12 +1410,12 @@ font-weight: 1000;" href="/watch?v=<%= x.videoId %>" class="title max-lines-2"><
<a href="/channel?id=<%= x.authorId %>"><%= x.author %><% if (x?.authorVerified) { %>
<i class="icon ion ion-md-checkmark-circle" title="verified channel"></i><% } %></a>
<div style="display: inline-flex;flex-direction: row;min-width: 6em;gap: 4px;">
<a href="/download?v=<%= x.videoId %>" style="background: #333;width: 7.6em;border-radius: 18px;">
<a href="/download?v=<%= x.videoId %>" style="background: #333;width: 7.6em;border-radius: 8px;">
<div style="display: flex;">
<i class="fa-light fa-download" style="display: flex;font-size: 16px;padding: 5px;border-radius: 18px;margin-left: 2px;"></i><span style="margin-top: 6px;">Download</span>
</div>
</a>
<a href="https://youtube.com/watch?v=<%= x.videoId %>" style="background: #333;width: 7.6em;border-radius: 18px;height: 2em;width: 12.5em;">
<a href="https://youtube.com/watch?v=<%= x.videoId %>" style="background: #333;width: 7.6em;border-radius: 8px;height: 2em;width: 12.5em;">
<div style="display: flex;">
<i class="fa-brands fa-youtube" style="display: flex;font-size: 16px;padding: 5px;border-radius: 18px;margin-left: 2px;"></i><span style="margin-top: 6px;">Open on YouTube :/</span>
</div>
@ -1055,12 +1447,12 @@ font-weight: 1000;" href="/watch?v=<%= x.videoId %>" class="title max-lines-2"><
<i class="icon ion ion-md-checkmark-circle" title="verified channel"></i><% } %></a>
</div>
<div style="display: inline-flex;flex-direction: row;min-width: 6em;gap: 4px;">
<a href="/download?v=<%= x.videoId %>" style="background: #333;width: 7.6em;border-radius: 18px;">
<a href="/download?v=<%= x.videoId %>" style="background: #333;width: 7.6em;border-radius: 8px;">
<div style="display: flex;">
<i class="fa-light fa-download" style="display: flex;font-size: 16px;padding: 5px;border-radius: 18px;margin-left: 2px;"></i><span style="margin-top: 6px;">Download</span>
</div>
</a>
<a href="https://youtube.com/watch?v=<%= x.videoId %>" style="background: #333;width: 7.6em;border-radius: 18px;height: 2em;width: 12.5em;">
<a href="https://youtube.com/watch?v=<%= x.videoId %>" style="background: #333;width: 7.6em;border-radius: 8px;height: 2em;width: 12.5em;">
<div style="display: flex;">
<i class="fa-brands fa-youtube" style="display: flex;font-size: 16px;padding: 5px;border-radius: 18px;margin-left: 2px;"></i><span style="margin-top: 6px;">Open on YouTube :/</span>
</div>

View File

@ -16,174 +16,8 @@
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 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;
margin: 10px 0;
}
.wrap.languages {
margin-bottom: 30px;
}
.item {
width: 100%;
height: 150px;
border-radius: 0.5em;
}
.item-wrapper {
display: flex;
justify-content: center;
width: 450px;
margin: 5px 10px;
}
button,
select,
input,
textarea {
border-radius: 1em;
padding: 10px;
background-color: #131618;
border: 2px solid #495057;
color: #f8f9fa;
}
body {
justify-content: center;
font-family: sans-serif;
background-color: #2c2f33;
color: #f8f9fa;
}
#translation-form {
background-color: #1f2023;
border-radius: 1em;
padding: 20px;
width: 90%;
max-width: 800px;
margin: auto;
box-shadow: 0 0 15px rgba(0, 0, 0, 0.3);
}
h1 {
color: #5bc0de;
font-size: 2rem;
}
#definitions_and_translations {
display: grid;
width: 100%;
grid-template-areas: "definitions translations";
gap: 20px;
}
@media screen and (max-width: 1200px) {
#definitions_and_translations {
display: grid;
grid-template-areas:
"definitions definitions"
"translations translations";
}
}
div.definitions,
div.translations {
padding: 10px;
background-color: #3a3f44;
border-radius: 0.5em;
}
textarea:focus,
input:focus,
button:focus {
border-color: #478061;
outline: 1px solid #478061;
}
a {
color: #599bf6;
}
/* Additional styles to match the calendar page */
header {
margin-bottom: 20px;
}
#switchbutton {
white-space: nowrap;
}
button {
font-size: 1rem;
}
.center button {
margin-top: 15px;
}
/* Responsive design */
@media screen and (max-width: 768px) {
#translation-form {
padding: 10px;
}
.wrap {
flex-direction: column;
}
.item-wrapper {
width: 100%;
}
}
</style>
<% if (isMobile) { %>
<style>
body {
overflow: auto;
}
</style>
<% } %>
<% if (!isMobile) { %>
<style>
body {
overflow: hidden;
}
</style>
<% } %>
</head>
<body>
<div id="translation-form">
<header class="center">
<h1>PokeTranslate</h1>
</header>
<% const languageOptions = [
<% const languageOptions = [
{ code: 'autodetect', name: 'Autodetect' },
{ code: 'af', name: 'Afrikaans' },
{ code: 'sq', name: 'Albanian' },
@ -279,70 +113,284 @@
{ code: 'yo', name: 'Yoruba' },
{ code: 'zu', name: 'Zulu' }
]; %>
<form action="/translate" method="GET" id="translation-form">
<!-- from and to language -->
<div class="wrap languages">
<div class="language">
<!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 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">
<link href="https://fonts.bunny.net/css?family=poppins:400,500,600" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<style>
:root {
--accent-1: #ff6b6b;
--accent-2: #f7d794;
--bg-light: #fafafa;
--bg-dark: #202027;
--card-light: rgba(255,255,255,0.55);
--card-dark: rgba(18,18,24,0.55);
--radius: 20px;
--transition: 0.3s ease;
}
* { margin:0; padding:0; box-sizing:border-box; }
body {
font-family:'Poppins',sans-serif;
background: var(--bg-light);
color: #fff;
display:flex; align-items:center; justify-content:center;
min-height:100vh; padding:20px;
transition: background var(--transition), color var(--transition);
overflow:hidden;
}
@media (prefers-color-scheme: dark) {
body { background: var(--bg-dark); }
}
.glass {
position: relative;
background: var(--card-light);
backdrop-filter: blur(30px) saturate(200%);
border-radius: var(--radius);
box-shadow: 0 8px 32px rgba(0,0,0,0.1);
width:100%; max-width:840px; overflow:hidden;
transition: background var(--transition), box-shadow var(--transition);
}
@media (prefers-color-scheme: dark) {
.glass {
background: var(--card-dark);
box-shadow: 0 8px 32px rgba(0,0,0,0.7);
}
}
.blob {
position:absolute; width:300px; height:300px;
background: linear-gradient(45deg,var(--accent-1),var(--accent-2));
border-radius: 45% 55% 70% 30%/30% 60% 40% 70%;
animation: blobMove 8s infinite; opacity:0.3; z-index:0;
}
.blob:nth-child(1){ top:-80px; left:-60px; }
.blob:nth-child(2){ bottom:-100px; right:-80px; animation-duration:10s; }
@keyframes blobMove {
0%,100% { transform:translate(0,0) scale(1); }
50% { transform:translate(20px,20px) scale(1.1); }
}
header {
position:relative; padding:28px; text-align:center;
background: linear-gradient(60deg,var(--accent-1),var(--accent-2));
background-size:200% 200%; animation:gradientAnimation 6s ease infinite;
z-index:1;
}
@keyframes gradientAnimation {
0%{ background-position:0% 50%; }
50%{ background-position:100% 50%; }
100%{ background-position:0% 50%; }
}
/* Rainbow title unless user prefers reduced motion */
@media (prefers-reduced-motion: no-preference) {
header h1 {
font-size:2.4rem; font-weight:600; letter-spacing:1.5px;
background: conic-gradient(red,orange,yellow,green,blue,indigo,violet,red);
background-size:300%;
-webkit-background-clip:text;
-webkit-text-fill-color:transparent;
animation: rainbow 4s linear infinite;
}
@keyframes rainbow {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
}
@media (prefers-reduced-motion: reduce) {
header h1 {
font-size:2.4rem; font-weight:600; letter-spacing:1.5px;
color:#fff;
}
}
form { position:relative; z-index:2; }
.language-bar { display:flex; align-items:center; gap:12px; padding:16px 24px; }
.language-select { flex:1; }
.language-select select {
width:100%; padding:14px 18px; border-radius:var(--radius);
border:1px solid rgba(255,255,255,0.5); background:transparent;
font-size:1rem; appearance:none; cursor:pointer; color:#fff;
transition:border-color var(--transition);
}
.language-select select:focus { border-color:var(--accent-1); outline:none; }
.swap-button {
font-size:2rem; color:var(--accent-1); text-decoration:none;
transition:transform var(--transition),color var(--transition);
}
.swap-button:hover {
transform:rotate(180deg) scale(1.1);
color:var(--accent-2);
}
.panels {
display:grid; grid-template-columns:1fr 1fr; gap:20px;
padding:0 24px 24px;
}
.panel { position:relative; }
.panel label {
display:block; margin-bottom:8px; font-weight:500; font-size:0.95rem;
color:#fff;
}
.panel textarea {
width:100%; min-height:160px; padding:16px; border-radius:var(--radius);
border:1px solid rgba(255,255,255,0.5); resize:vertical; font-size:1rem;
line-height:1.5; background:rgba(255,255,255,0.2); color:#fff;
transition:border-color var(--transition),box-shadow var(--transition);
}
.panel textarea::placeholder { color:rgba(255,255,255,0.7); }
@media (prefers-color-scheme: dark) {
.panel textarea { background:rgba(20,20,25,0.5); }
}
.panel textarea:focus {
border-color:var(--accent-1);
box-shadow:0 0 8px var(--accent-1);
outline:none;
}
.actions { display:flex; justify-content:center; padding-bottom:24px; }
.actions button {
padding:16px 36px; font-size:1.1rem; font-weight:600; border:none;
border-radius:var(--radius); cursor:pointer;
background:linear-gradient(60deg,var(--accent-1),var(--accent-2));
background-size:200% 200%; animation:gradientAnimation 6s ease infinite;
color:#fff; box-shadow:0 4px 14px rgba(0,0,0,0.2);
transition:transform var(--transition),opacity var(--transition);
}
.actions button:hover { transform:scale(1.03); opacity:0.9; }
@media (max-width:768px) { .panels { grid-template-columns:1fr; } }
</style>
</head>
<body>
<div class="glass">
<div class="blob"></div>
<div class="blob"></div>
<header><h1>PokeTranslate</h1></header>
<form action="/translate" method="GET">
<div class="language-bar">
<div class="language-select">
<select name="from_language" id="from_language">
<% languageOptions.forEach(language => { %>
<option value="<%= language.code %>" <%= language.code === (from_language || 'autodetect') ? 'selected' : '' %>>
<%= language.name %>
<% languageOptions.forEach(lang => { %>
<option value="<%= lang.code %>" <%= lang.code === (from_language||'autodetect')?'selected':''%>>
<%= lang.name %>
</option>
<% }); %>
</select>
</div>
<a
href="?from_language=<%= to_language %>&to_language=<%= from_language %>&input=<%= encodeURIComponent(text) %>"
id="swapBtn"
class="material-icons swap-button"
>swap_horiz</a>
<div class="language-select">
<select name="to_language" id="to_language">
<% languageOptions.slice(1).forEach(language => { %>
<option value="<%= language.code %>" <%= language.code === to_language ? 'selected' : '' %>>
<%= language.name %>
<% languageOptions.slice(1).forEach(lang => { %>
<option value="<%= lang.code %>" <%= lang.code===to_language?'selected':''%>>
<%= lang.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 class="panels">
<div class="panel input">
<label for="input">Input</label>
<textarea id="input" name="input" placeholder="Enter text…"><%= text %></textarea>
</div>
<div class="item-wrapper">
<textarea id="output" class="translation item" dir="auto" placeholder="Translation" readonly>
<%- translation %>
</textarea>
<div class="panel output">
<label for="output">Translation</label>
<textarea id="output" readonly placeholder="Translated text…"><%= translation %></textarea>
</div>
</div>
<div class="center">
<div class="actions">
<button type="submit">Translate :3</button>
</div>
</form>
</div>
<script>
document.getElementById("input").addEventListener("keydown", function (event) {
if (event.keyCode === 13 && (event.metaKey || event.ctrlKey)) {
document.getElementById("translation-form").submit();
(function(){
// swap button
const swapBtn = document.getElementById('swapBtn');
if(swapBtn){
swapBtn.addEventListener('click', function(e){
e.preventDefault();
const from = document.getElementById('from_language');
const to = document.getElementById('to_language');
const inp = document.getElementById('input');
const out = document.getElementById('output');
[from.value, to.value] = [to.value, from.value];
[inp.value, out.value] = [out.value, inp.value];
});
}
// auto-resize all textareas
document.querySelectorAll('textarea').forEach(el=>{
const resize = ()=>{ el.style.height='auto'; el.style.height=el.scrollHeight+'px'; };
el.addEventListener('input', resize);
resize();
});
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";
// live-translate if JS available
if(window.fetch){
const from = document.getElementById('from_language');
const to = document.getElementById('to_language');
const input = document.getElementById('input');
const output= document.getElementById('output');
let timer;
function translateNow(){
const q = new URLSearchParams({
from_language: from.value,
to_language: to.value,
input: input.value
});
fetch(`/translate?${q}`)
.then(r => r.text())
.then(html => {
const doc = new DOMParser().parseFromString(html, 'text/html');
const newOut = doc.getElementById('output');
if(newOut){
output.value = newOut.value;
output.dispatchEvent(new Event('input'));
}
})
.catch(() => {/* ignore */});
}
// debounce on typing
input.addEventListener('input', ()=>{
clearTimeout(timer);
timer = setTimeout(translateNow, 500);
});
// re-translate on language change
from.addEventListener('change', translateNow);
to.addEventListener('change', translateNow);
}
})();
</script>
<script src="/static/custom-css.js"></script>
</body>
</html>

View File

@ -12,7 +12,7 @@
if (!isValidYouTubeID(v) || isLetterSpam(v)) {
reason = "Video not found >~<";
} else {
reason = "This helps protect our community. Learn more (TRYING AGAIN....)";
reason = "Poke is currently restarting - please wait 1-2 minutes..";
}
%>

View File

@ -967,7 +967,8 @@ Offical Discord Server! :3
</a>
</div>
</div>
<a href="/app" class="account"><i class="fa-light fa-compass"></i>Discover!</a>
<a href="/game-hub" class="account" style="margin-right: 4px;"><i class="fa-light fa-gamepad"></i>Games!</a>
<a href="/app" class="account"><i class="fa-light fa-compass"></i>Discover!</a>
</div>
</nav>
@ -1024,7 +1025,7 @@ Offical Discord Server! :3
<% if (itag && !qua) { %>
<audio id="aud" preload>
<source src="<%=u%>/latest_version?id=<%=inv_vid.videoId%>&itag=<%=itag%>&local=true" type="video/mp4" onerror="setTimeout(function() { location.reload(); }, 5000);" />
<source src="<%=u%>/latest_version?id=<%=inv_vid.videoId%>&itag=<%=itag%>&local=true" type="video/mp4" />
</audio>
<% } else { %>
<audio id="aud"></audio>
@ -1038,7 +1039,7 @@ Offical Discord Server! :3
<% } %>
</noscript>
<video poster="<%- media_proxy_url %>/proxy?url=https://i.ytimg.com/vi/<%= inv_vid.videoId %>/hqdefault.jpg" class="video-js player video-ambient-container" id="video" style="border-radius: 16px; box-sizing: border-box; min-width: 100%; display: block;" preload onerror="setTimeout(function() { location.reload(); }, 5000);">
<video poster="<%- media_proxy_url %>/proxy?url=https://i.ytimg.com/vi/<%= inv_vid.videoId %>/hqdefault.jpg" class="video-js player video-ambient-container" id="video" style="border-radius: 16px; box-sizing: border-box; min-width: 100%; display: block;" preload>
<% if (isvidious) { %>
<% if (!qua) { %>
<%
@ -1049,10 +1050,10 @@ Offical Discord Server! :3
}
});
%>
<source src="<%=u%>/latest_version?id=<%=inv_vid.videoId%>&itag=<%=itag%>&local=true" type="video/mp4; codecs=&quot;avc1.64001F, mp4a.40.2&quot;" label="hd720" selected="true" onerror="setTimeout(function() { location.reload(); }, 5000);">
<source src="<%=u%>/latest_version?id=<%=inv_vid.videoId%>&itag=<%=itag%>&local=true" type="video/mp4; codecs=&quot;avc1.64001F, mp4a.40.2&quot;" label="hd720" selected="true">
<% } %>
<% if (qua === "medium") { %>
<source src="<%=u%>/latest_version?id=<%=inv_vid.videoId%>&itag=18&local=true" type="video/mp4; codecs=&quot;avc1.64001F, mp4a.40.2&quot;" label="sd360" selected="true" onerror="onerror="setTimeout(function() { location.reload(); }, 5000);"">
<source src="<%=u%>/latest_version?id=<%=inv_vid.videoId%>&itag=18&local=true" type="video/mp4; codecs=&quot;avc1.64001F, mp4a.40.2&quot;" label="sd360" selected="true" >
<% } %>
<% } %>
@ -1783,7 +1784,7 @@ WIP! </a>
</p>
</div>
<% inv.comments.forEach(x =>{ %><div class="fade-in<%- x.commentId %><%- btoa(x.commentId) %>"><div class="_ comment_<%- x.commentId %><%- btoa(btoa(x.commentId)) %>"style="padding:10px"><div class="comment-list left-padding"style="background:#333;padding-top:1px;padding:10px;border-radius:30px;padding-top:0"><div class="d-flex justify-content-between single-comment"style="padding-top:none"><div class="d-flex justify-content-between user"><div class="desc"><h5 style="display:flex;margin-top:7px;padding-top:10px"><div class="thumb"><a href="/channel?id=<%- x.authorId%>@youtube.com"style="width:40px;height:40px"class="avatar"><img loading="lazy"src="<%- media_proxy_url %>/proxy?url=<%= x.authorThumbnails[0].url.replace("https://yt3.ggpht.com/", "https://vid.puffyan.us/ggpht/") %>"></a></div><% if (!x.authorIsChannelOwner) { %><p class="comments-author"><a href="/channel?id=<%- x.authorId%>"style="color:var(--text-color);text-decoration:none"><%- x.author%><% if (x.verified) { %><i class="icon ion ion-md-checkmark-circle"></i><% } %><p class="date-publish"><%- x.publishedText %></p></a></p><% } %><% if (x.authorIsChannelOwner) { %><p class="comments-author owner"><a href="/channel?id=<%- x.authorId%>@youtube.com"style="color:var(--text-color);text-decoration:none"><%- x.author%><% if (x.verified) { %><i class="icon ion ion-md-checkmark-circle"></i><% } %><p class="date-publish"><%- x.publishedText %></p></a><% } %></h5><p class="comment"style="font-weight:700"><%- x.contentHtml.replace(/\n/g, "<br>"); %><br><br><% if (x.likeCount === 0) { %><i class="fa-light fa-thumbs-up"></i> | <i class="fa-light fa-thumbs-down"></i><% } else { %><i class="fa-light fa-thumbs-up"></i> <%= convert(x.likeCount) %> | <i class="fa-light fa-thumbs-down"></i><% } %><% if(x.creatorHeart) { %> <i class="icon creator-heart-small-container ion-ios-heart"style="color:#ffabcc"title="<%= x.creatorHeart.creatorName%> marked it with a ❤ owo"></i><% } %></div></div></div></div></div></div><% }) %>
<% inv.comments.forEach(x =>{ %> <div class="fade-in<%- x.commentId %><%- btoa(x.commentId) %>"><div class="_ comment_<%- x.commentId %><%- btoa(btoa(x.commentId)) %>" style="padding:10px"><div class="comment-list left-padding" style="background:#333;padding-top:1px;padding:10px;border-radius:30px;padding-top:0"><div class="d-flex justify-content-between single-comment" style="padding-top:none"><div class="d-flex justify-content-between user"><div class="desc"><h5 style="display:flex;margin-top:7px;padding-top:10px"><div class="thumb"><a href="/channel?id=<%- x.authorId%>@youtube.com" style="width:40px;height:40px" class="avatar"><img loading="lazy" src="<%- media_proxy_url %>/proxy?url=<%= x.authorThumbnails[0].url.replace("https://yt3.ggpht.com/", "https://vid.puffyan.us/ggpht/") %>"></a></div> <% if (!x.authorIsChannelOwner) { %> <p class="comments-author"><a href="/channel?id=<%- x.authorId%>" style="color:var(--text-color);text-decoration:none"> <%- x.author%><% if (x.verified) { %><i class="icon ion ion-md-checkmark-circle"></i><% } %> <p class="date-publish"><%- x.publishedText %></p></a></p> <% } %><% if (x.authorIsChannelOwner) { %> <p class="comments-author owner"><a href="/channel?id=<%- x.authorId%>@youtube.com" style="color:var(--text-color);text-decoration:none"> <%- x.author%><% if (x.verified) { %><i class="icon ion ion-md-checkmark-circle"></i><% } %> <p class="date-publish"><%- x.publishedText %></p></a> <% } %> </p></h5><p class="comment" style="font-weight:700"> <%- x.contentHtml.replace(/\n/g, "<br />"); %><br><br> <% if (x.likeCount === 0) { %><i class="fa-light fa-thumbs-up"></i>|<i class="fa-light fa-thumbs-down"></i><% } else { %><i class="fa-light fa-thumbs-up"></i> <%= convert(x.likeCount) %> |<i class="fa-light fa-thumbs-down" style="margin-right: 5px;"></i><% } %> <% if (x.replies?.replyCount != 0) { %> <i class="fa-light fa-reply"></i> <%- x.replies?.replyCount || "0" %> <% } %> <% if(x.creatorHeart) { %> <i class="icon creator-heart-small-container ion-ios-heart" style="color:#ffabcc" title="<%= x.creatorHeart.creatorName%> marked it with a ❤ owo"></i><% } %> </p></div></div></div></div></div></div> <% }) %>
<center>
<a href="#top">Go To Top</a>
</center>
@ -1837,12 +1838,6 @@ WIP! </a>
<input title="autoplay the next video" name="continue" id="continue" type="checkbox" >
</div>
<div style="text-align: right;margin-top: -2.2em;width: 1em; margin-left: auto; margin-right: 5px;" >
<a title="Upload content :3" href="/video/upload">
<i class="fa-light fa-circle-plus"></i>
</a>
</div>
<% if (!f) { %>
@ -2575,12 +2570,6 @@ a {
<% } %>
<% if (qua === "medium") { %>
<source src="https://eu-proxy.poketube.fun/latest_version?id=<%=inv_vid.videoId%>&itag=18&local=true" type="video/mp4; codecs=&quot;avc1.64001F, mp4a.40.2&quot;" label="sd360" selected="true">
<% } %>
@ -2921,6 +2910,9 @@ font-size: 13px;margin:0;padding:0;white-space: nowrap;
const userScoreColor = userScore >= 80 ? 'green' : userScore >= 50 ? 'orange' : 'red';
%>
<div class="nerddd" style="background:#272727;padding: 5px;margin-top: 12px;border-radius: 11px;font-family: 'PokeTube Flex';font-stretch: extra-expanded;font-weight: 700;">
<a href="https://chatgpt.com/?q=<%- inv_vid.description %>+Please+summarize+the+selection+using+precise+and+concise+language.+Use+headers+and+bulleted+lists+in+the+summary%2C+to+make+it+scannable.+Maintain+the+meaning+and+factual+accuracy.">SUMMERISE!</a>
<%-String(channelurlfixer(inv_vid.descriptionHtml)).replace(/\n/g, " <br> ").replace(/twitter\.com/g, "twitter.com").replace(/reddit\.com/g, "redlib.matthew.science") %>

View File

@ -35,7 +35,7 @@
"activitypub-express": "^4.4.1",
"duck-duck-scrape": "^2.2.5",
"google-it": "^1.6.4",
"youtubei.js": "^9.3.0"
"youtubei.js": "^13.4.0"
},
"engines": {
"node": ">=18"

View File

@ -23,7 +23,6 @@ var ping = require("ping");
const sha384 = modules.hash;
const splash = [
"Woke!",
"Gay gay homosexaul gay!",
@ -131,10 +130,7 @@ const splash = [
"stallmansupport.org!!!",
"does include nya~!!!",
"actually stable! :3",
]
];
function getJson(str) {
try {
@ -153,13 +149,16 @@ module.exports = function (app, config, renderTemplate) {
tab = `/?type=${capitalizeFirstLetter(req.query.tab)}`;
}
const invtrend = await fetch(
`${config.invapi}/trending${tab}`
);
const invtrend = await fetch(`${config.invapi}/trending${tab}`, {
headers: { "User-Agent": config.useragent },
});
const t = getJson(await invtrend.text());
const invpopular = await fetch(
`https://invid-api.poketube.fun/bHj665PpYhUdPWuKPfZuQGoX/api/v1/popular`
`https://invid-api.poketube.fun/bHj665PpYhUdPWuKPfZuQGoX/api/v1/popular`,
{
headers: { "User-Agent": config.useragent },
}
);
const p = getJson(await invpopular.text());
@ -190,18 +189,15 @@ module.exports = function (app, config, renderTemplate) {
const uaos = req.useragent.os;
const random = splash[Math.floor(Math.random() * splash.length)];
const browser = req.useragent.browser;
const isOldWindows = (uaos === "Windows 7" || uaos === "Windows 8") && browser === "Firefox";
const isOldWindows =
(uaos === "Windows 7" || uaos === "Windows 8") &&
browser === "Firefox";
var proxyurl = config.p_url;
const secure = [
"poketube.fun",
"localhost" //
].includes(req.hostname);
const verify = [
"poketube.fun",
"poke.ashley0143.xyz",
"localhost"
].includes(req.hostname);
const secure = ["poketube.fun", "localhost"].includes(req.hostname);
const verify = ["poketube.fun", "poke.ashley0143.xyz", "localhost"].includes(
req.hostname
);
const rendermainpage = () => {
if (req.useragent.isMobile) {
@ -210,13 +206,13 @@ module.exports = function (app, config, renderTemplate) {
return renderTemplate(res, req, "landing.ejs", {
secure,
embedtype:req.query.embedtype,
banner:config.banner,
DisablePokeChan:req.query.DisablePokeChan,
embedtype: req.query.embedtype,
banner: config.banner,
DisablePokeChan: req.query.DisablePokeChan,
verify,
isOldWindows,
proxyurl,
random
random,
});
};
@ -225,10 +221,10 @@ module.exports = function (app, config, renderTemplate) {
if (isvld && req.params.v.length >= 10) {
return res.redirect(`/watch?v=${req.params.v}`);
} else {
res.status(404)
res.status(404);
return renderTemplate(res, req, "404.ejs", {
isOldWindows,
random
random,
});
}
}

View File

@ -1,22 +1,5 @@
const {
fetcher,
core,
wiki,
musicInfo,
modules,
version,
initlog,
init,
} = require("../libpoketube-initsys.js");
const {
IsJsonString,
convert,
getFirstLine,
capitalizeFirstLetter,
turntomins,
getRandomInt,
getRandomArbitrary,
} = require("../ptutils/libpt-coreutils.js");
const { modules } = require("../libpoketube-initsys.js");
var http = require("https");
var ping = require("ping");

View File

@ -1,22 +1,4 @@
const {
fetcher,
core,
wiki,
musicInfo,
modules,
version,
initlog,
init,
} = require("../libpoketube-initsys.js");
const {
IsJsonString,
convert,
getFirstLine,
capitalizeFirstLetter,
turntomins,
getRandomInt,
getRandomArbitrary,
} = require("../ptutils/libpt-coreutils.js");
const { modules, version } = require("../libpoketube-initsys.js");
function getJson(str) {
try {
@ -29,36 +11,43 @@ function getJson(str) {
const pkg = require("../../../package.json");
const os = require('os');
const cnf = require("../../../config.json");
const innertube = require("../libpoketube-youtubei-objects.json");
const { execSync } = require('child_process');
const verfull = "v24.1906-sho-MAJOR_UPDATE-stable-dev-nonLTS-git-MTcxODc5NDY3NQ==";
const versmol = "v24.1906-sho"
const { execSync } = require('child_process'); // DO NOT ABBRV THIS :SOB:
const verfull = "v25.2705-luna-MAJOR_UPDATE-stable-dev-nonLTS-git-MTc0NTcwNjc4MA==";
const versmol = "v25.2705-luna";
const branch = "dev/master";
const codename = "sho";
const versionnumber = "293";
const relaseunixdate = "MTcxODc5NDY3NQ=="
const updatequote = "pls fund vennie plush -Bims"
const codename = "luna";
const versionnumber = "294";
const relaseunixdate = "MTc0NTcwNjc4MA==";
const updatequote = "i created this world.....to feel some control...";
module.exports = function (app, config, renderTemplate) {
const headers = {
'User-Agent': config.useragent,
};
app.get("/vi/:v/:t", async function (req, res) {
var url = `https://i.ytimg.com/vi/${req.params.v}/${req.params.t}`
var url = `https://i.ytimg.com/vi/${req.params.v}/${req.params.t}`;
let f = await modules.fetch(url + `?cachefixer=${btoa(Date.now())}`, {
method: req.method,
headers: headers,
});
f.body.pipe(res);
});
app.get("/avatars/:v", async function (req, res) {
app.get("/avatars/:v", async function (req, res) {
var url = `https://vid.puffyan.us/ggpht/${req.params.v}`;
let f = await modules.fetch(url + `?cachefixer=${btoa(Date.now())}`, {
method: req.method,
headers: headers,
});
f.body.pipe(res);
@ -69,39 +58,30 @@ app.get("/avatars/:v", async function (req, res) {
let f = await modules.fetch(url + `?cachefixer=${btoa(Date.now())}`, {
method: req.method,
headers: headers,
});
f.body.pipe(res);
});
app.get("/avatars/ytc/:v", async function (req, res) {
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,
headers: headers,
});
f.body.pipe(res);
});
app.get("/api/search", async (req, res) => {
const query = req.query.query;
if (!query) {
return res.redirect("/");
}
return res.redirect(`/search?query=${query}`);
});
app.get("/api/video/download", async function (req, res) {
var v = req.query.v;
var q = "18";
if (req.query.q) q = req.query.q;
const url = `https://eu-proxy.poketube.fun/latest_version?id=${v}&itag=${q}&local=true`;
const url = `${config.videourl}latest_version?id=${v}&itag=${q}&local=true`;
res.redirect(url);
});
@ -113,9 +93,12 @@ app.get("/avatars/:v", async function (req, res) {
const l = req.query.h;
try {
let url = `https://eu-proxy.poketube.fun/api/v1/captions/${id}?label=${l}`;
let url = `${config.videourl}/api/v1/captions/${id}?label=${l}`;
let f = await fetch(url, {
headers: headers,
});
let f = await fetch(url);
const body = await f.text();
res.send(body);
@ -131,7 +114,9 @@ app.get("/avatars/:v", async function (req, res) {
if (id) {
const apiUrl = `https://ryd-proxy.kavin.rocks/votes/${id}&hash=d0550b6e28c8f93533a569c314d5b4e2`;
const response = await fetch(apiUrl);
const response = await fetch(apiUrl, {
headers: headers,
});
if (response.status === 400) {
const error = await response.json();
@ -222,50 +207,8 @@ app.get("/avatars/:v", async function (req, res) {
} catch (error) {
res.status(500).json("whoops (error 500) >~<");
}
});
app.use("/sb/i/:v/:imagePath/:img", async function (req, res) {
const { v, imagePath, img } = req.params;
const { sqp, xywh } = req.query;
const sighMatch = req.url.match(/&amp;sigh=([^&#]+)/);
const sigh = sighMatch ? sighMatch[1] : undefined;
const url = `https://yt.miruku.cafe/sb/i/${v}/${imagePath}/${img}?sqp=${sqp}&sigh=${sigh}&xywh=${req.query.xywh}`;
try {
let f = await modules.fetch(url + `?cachefixer=${btoa(Date.now())}`, {
method: req.method,
});
f.body.pipe(res);
console.log(url)
} catch (error) {
console.error("Error fetching image:", error);
res.status(500).send("Error fetching image");
}
});
app.get("/api/storyboards", async (req, res) => {
const { fetch } = await import("undici");
const id = req.query.v;
const l = req.query.h;
try {
let url = `https://yt.miruku.cafe/api/v1/storyboards/${id}?width=320&height=180`;
let f = await fetch(url);
let body = await f.text();
body = body.replace(/#xywh=(\d+),(\d+),(\d+),(\d+)/g, (match, x, y, w, h) => {
return `&xywh=${x},${y},${w},${h}`;
});
res.send(body);
} catch {}
});
app.get("/feeds/videos.xml", async (req, res) => {
const id = req.query.channel_id;
@ -273,6 +216,7 @@ app.use("/sb/i/:v/:imagePath/:img", async function (req, res) {
let f = await modules.fetch(url, {
method: req.method,
headers: headers, // Add headers to the fetch request
});
f.body.pipe(res);
@ -285,13 +229,12 @@ app.use("/sb/i/:v/:imagePath/:img", async function (req, res) {
let f = await modules.fetch(url, {
method: req.method,
headers: headers,
});
f.body.pipe(res);
});
app.get("/api/redirect", async (req, res) => {
const red_url = atob(req.query.u);
@ -314,7 +257,9 @@ app.use("/sb/i/:v/:imagePath/:img", async function (req, res) {
let latestCommitHash;
const invidious = await modules
.fetch("https://invid-api.poketube.fun/bHj665PpYhUdPWuKPfZuQGoX/api/v1/stats")
.fetch("https://invid-api.poketube.fun/bHj665PpYhUdPWuKPfZuQGoX/api/v1/stats", {
headers: headers,
})
.then((res) => res.text())
.then((txt) => getJson(txt));
@ -322,7 +267,7 @@ app.use("/sb/i/:v/:imagePath/:img", async function (req, res) {
const totalMemory = os.totalmem() / (1024 * 1024 * 1024);
const roundedMemory = totalMemory.toFixed(2);
execSync('git rev-list HEAD -n 1 --abbrev-commit', (error, stdout, stderr) => {
execSync('git rev-list HEAD -n 1 --abbrev-commit', (error, stdout, stderr) => {
if (error || stderr) {
console.error(`Error executing command: ${error || stderr}`);
return;
@ -330,22 +275,23 @@ execSync('git rev-list HEAD -n 1 --abbrev-commit', (error, stdout, stderr) => {
latestCommitHash = stdout.trim();
});
const { useragent, ...configWithoutUA } = cnf;
const response = {
pt_version: {
version:versmol,
version_full:verfull,
commit: latestCommitHash
version: versmol,
version_full: verfull,
commit: latestCommitHash,
},
branch,
updatequote,
relaseunixdate,
vernum: versionnumber,
codename,
config:cnf,
system:{
ram:`${roundedMemory} GB`,
cpu:cpus[0].model,
config: configWithoutUA,
system: {
ram: `${roundedMemory} GB`,
cpu: cpus[0].model,
},
packages: {
libpt: version,
@ -374,7 +320,9 @@ execSync('git rev-list HEAD -n 1 --abbrev-commit', (error, stdout, stderr) => {
try {
const url = `https://raw.githubusercontent.com/ashley0143/poke/main/instances.json`;
let f = await fetch(url)
let f = await fetch(url, {
headers: headers,
})
.then((res) => res.text())
.then((json) => JSON.parse(json));

View File

@ -135,7 +135,6 @@ module.exports = function (app, config, renderTemplate) {
res.redirect("https://lite.duckduckgo.com/lite/?q=" + query);
}
if (query && query.startsWith("Hey ChatGPT,") && query.length > 2) {
res.redirect("https://chatgpt.com/?q=" + query + "- sent using pokeAI features");
}
@ -153,18 +152,21 @@ module.exports = function (app, config, renderTemplate) {
try {
const headers = {};
let searchUrl;
if (req.query.from === 'hashtag') {
let searchUrl;
if (req.query.from === 'hashtag') {
searchUrl = `${config.invapi}/hashtag/${query}?hl=en-gb`;
} else {
} else {
searchUrl = `${config.invapi}/search?q=${encodeURIComponent(query)}&page=${encodeURIComponent(continuation)}&date=${date}&type=${type}&duration=${duration}&sort=${sort}&hl=en+gb`;
}
}
const xmlData = await fetch(searchUrl)
const xmlData = await fetch(searchUrl, {
headers: {
'User-Agent': config.useragent,
},
})
.then((res) => res.text())
.then((txt) => getJson(txt));
renderTemplate(res, req, "search.ejs", {
invresults: xmlData,
turntomins,
@ -218,7 +220,11 @@ const xmlData = await fetch(searchUrl)
try {
// about
const bout = await fetch(config.tubeApi + `channel?id=${ID}&tab=about`);
const bout = await fetch(config.tubeApi + `channel?id=${ID}&tab=about`, {
headers: {
'User-Agent': config.useragent,
},
});
const h = await bout.text();
var boutJson = JSON.parse(modules.toJson(h));
} catch {
@ -238,7 +244,11 @@ const xmlData = await fetch(searchUrl)
const getChannelData = async (url) => {
try {
return await fetch(url)
return await fetch(url, {
headers: {
'User-Agent': config.useragent,
},
})
.then((res) => res.text())
.then((txt) => getJson(txt));
} catch (error) {
@ -249,23 +259,23 @@ const xmlData = await fetch(searchUrl)
const apiUrl = config.invapi + "/channels/";
const channelUrl = `${apiUrl}${ID}/${atob(
ChannelTabs.videos
)}?sort_by=${sort_by}${continuation}`;
)}?sort_by=${sort_by}${continuation}`;
const shortsUrl = `${apiUrl}${ID}/${atob(
const shortsUrl = `${apiUrl}${ID}/${atob(
ChannelTabs.shorts
)}?sort_by=${sort_by}${continuation}`;
)}?sort_by=${sort_by}${continuation}`;
const streamUrl = `${apiUrl}${ID}/${atob(
const streamUrl = `${apiUrl}${ID}/${atob(
ChannelTabs.streams
)}?sort_by=${sort_by}${continuation}`;
)}?sort_by=${sort_by}${continuation}`;
const communityUrl = `${apiUrl}${ID}/${atob(
const communityUrl = `${apiUrl}${ID}/${atob(
ChannelTabs.community
)}?hl=en-US`;
)}?hl=en-US`;
const PlaylistUrl = `${apiUrl}${ID}/${atob(
const PlaylistUrl = `${apiUrl}${ID}/${atob(
ChannelTabs.playlist
)}?hl=en-US`;
)}?hl=en-US`;
const channelINVUrl = `${apiUrl}${ID}/`;
@ -280,22 +290,18 @@ const PlaylistUrl = `${apiUrl}${ID}/${atob(
getChannelData(channelINVUrl),
]);
var bannedchannels = ["UC1okSIA8UEY8OqvtjGHFvzA", "UClsVg5LkK2COQRo1mVS4taA", "UCIr4vkCsn0tdTW2xZ1jRG1g"];
var bypassQuery = "cG9rZXR1YmVjaGFubmVsYnlwYXNzbG9scGVvcGxldGhpbmt0aGlzaXNjZW5zb3JzaGlwLTQ1OTBh";
var bannedchannels = ["UC1okSIA8UEY8OqvtjGHFvzA", "UClsVg5LkK2COQRo1mVS4taA", "UCIr4vkCsn0tdTW2xZ1jRG1g"];
var bypassQuery = "cG9rZXR1YmVjaGFubmVsYnlwYXNzbG9scGVvcGxldGhpbmt0aGlzaXNjZW5zb3JzaGlwLTQ1OTBh";
var bypassExists = req.query.bypass === bypassQuery;
var tabExists = 'tab' in req.query;
var continuationExists = 'continuation' in req.query;
var bypassExists = req.query.bypass === bypassQuery;
var tabExists = 'tab' in req.query;
var continuationExists = 'continuation' in req.query;
if (bannedchannels.some(channel => channel === ID) && !bypassExists && !tabExists && !continuationExists) {
if (bannedchannels.some(channel => channel === ID) && !bypassExists && !tabExists && !continuationExists) {
var cinv = {
error:`this channel may include disinformation. If you still wanna view content <a href="/channel?id=${ID}&bypass=${bypassQuery}">click here</a> to bypass this restriction.`
error: `this channel may include disinformation. If you still wanna view content <a href="/channel?id=${ID}&bypass=${bypassQuery}">click here</a> to bypass this restriction.`
};
}
}
function getThumbnailUrl(video) {
const maxresDefaultThumbnail = video.videoThumbnails.find(
@ -333,8 +339,6 @@ if (bannedchannels.some(channel => channel === ID) && !bypassExists && !tabExist
);
const dnoreplace = about?.Description.toString();
let ChannelFirstVideoObject = {
subCountText: "0",
authorVerified: false,
@ -363,8 +367,7 @@ if (bannedchannels.some(channel => channel === ID) && !bypassExists && !tabExist
isMobile: req.useragent.isMobile,
about,
playlist,
subs:
typeof subscribers === "string"
subs: typeof subscribers === "string"
? subscribers.replace("subscribers", "")
: "None",
desc: dnoreplace === "[object Object]" ? "" : description,

View File

@ -115,27 +115,22 @@ module.exports = function (app, config, renderTemplate) {
app.get("/apps", function (req, res) {
renderTemplate(res, req, "apps.ejs");
});
app.get("/playlist", async function (req, res) {
const { fetch } = await import("undici");
const headers = { "User-Agent": config.useragent };
app.get("/playlist", async function (req, res) {
if (!req.query.list) res.redirect("/");
if (req.useragent.isMobile) res.redirect("/");
const playlist = await fetch(
`${config.invapi}/playlists/${req.query.list}?hl=en-us`
);
const playlist = await fetch(`${config.invapi}/playlists/${req.query.list}?hl=en-us`, { headers });
const p = getJson(await playlist.text());
var mediaproxy = config.media_proxy;
if (req.useragent.source.includes("Pardus")) {
var mediaproxy = "https://media-proxy.ashley0143.xyz";
mediaproxy = "https://media-proxy.ashley0143.xyz";
}
renderTemplate(res, req, "playlist.ejs", { p, mediaproxy });
});
renderTemplate(res, req, "playlist.ejs", {
p,
mediaproxy,
});
});
app.get("/license", function (req, res) {
renderTemplate(res, req, "license.ejs");
@ -261,7 +256,7 @@ app.get('/calendar', (req, res) => {
});
app.get("/game-hub", function (req, res) {
var gameslist = ["pong", "tic-tac-toe", "sudoku", "snake"];
var gameslist = ["pong", "tic-tac-toe", "sudoku", "snake", "breakout", "minesweeper"];
var requestedGame = req.query.game;
if (req.query.game && !gameslist.includes(requestedGame)) {

View File

@ -452,7 +452,7 @@ module.exports = function (app, config, renderTemplate) {
var vidurl = u.losslessurl;
}
var vidurl = "https://eu-proxy.poketube.fun";
var vidurl = config.videourl;
var isvidious = true;
if (req.useragent.source.includes("Pardus")) {

View File

@ -12,20 +12,7 @@ const getdislikes = require("../libpoketube/libpoketube-dislikes.js");
const getColors = require("get-image-colors");
const config = require("../../config.json")
/**
* Class representing PokeTube's core functionality.
*/
class InnerTubePokeVidious {
/**
* Create an instance of InnerTubePokeVidious.
* @param {object} config - Configuration object for InnerTubePokeVidious.
* @param {string} config.tubeApi - Tube API URL.
* @param {string} config.invapi - Invid API URL.
* @param {string} config.invapi_alt - Invid API URL - ALT .
* @param {string} config.dislikes - Dislikes API URL.
* @param {string} config.t_url - Matomo URL.
*/
constructor(config) {
this.config = config;
this.cache = {};
@ -36,17 +23,12 @@ class InnerTubePokeVidious {
this.ANDROID_API_KEY = "AIzaSyA8eiZmM1FaDVjRy-df2KTyQ_vz_yYM39w"
this.ANDROID_APP_VERSION = "19.14.42"
this.ANDROID_VERSION = "13"
this.useragent = "com.google.android.youtube/19.14.42 (Linux; U; Android 12; US) gzip"
this.useragent = config.useragent || "PokeTube/2.0.0 (GNU/Linux; Android 14; Trisquel 11; poketube-vidious; like FreeTube)"
this.INNERTUBE_CONTEXT_CLIENT_VERSION = "1"
this.region = "region=US";
this.sqp = "-oaymwEbCKgBEF5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLBy_x4UUHLNDZtJtH0PXeQGoRFTgw";
}
/**
* Fetch JSON from API response.
* @param {string} str - String response from the API.
* @returns {object|null} Parsed JSON object or null if parsing failed.
*/
getJson(str) {
try {
return JSON.parse(str);
@ -55,92 +37,68 @@ class InnerTubePokeVidious {
}
}
/**
* Check if the provided object has the required properties.
* @param {object} obj - Object to check.
* @returns {boolean} True if the object has the required properties, false otherwise.
*/
checkUnexistingObject(obj) {
if (obj) {
if ("authorId" in obj) {
return true;
}
}
return obj && "authorId" in obj;
}
/**
* Fetch video information.
* @param {string} v - Video ID.
* @returns {Promise<object>} Promise resolving to the video information.
*/
async getYouTubeApiVideo(f, v, contentlang, contentregion) {
const { fetch } = await import("undici");
if (v == null) return "Gib ID";
// Check if result is already cached
if (this.cache[v] && Date.now() - this.cache[v].timestamp < 3600000) {
return this.cache[v].result;
}
const headers = {};
let desc = "";
const headers = {
"User-Agent": this.useragent,
};
const fetchWithRetry = async (url, options = {}, retries = 3) => {
for (let attempt = 0; attempt < retries; attempt++) {
const res = await fetch(url, options);
if (res.status === 500 && attempt < retries - 1) {
continue; // retry on 500
const res = await fetch(url, {
...options,
headers: {
...options.headers,
...headers,
}
});
if (res.status === 500 && attempt < retries - 1) continue;
return res;
}
// If all retries fail, return last response
return null;
};
try {
const [invComments, videoInfo, videoData] = await Promise.all([
fetchWithRetry(`${this.config.invapi}/comments/${v}?hl=${contentlang}&region=${contentregion}&h=${btoa(Date.now())}`).then((res) => res.text()),
fetchWithRetry(`${this.config.invapi}/videos/${v}?hl=${contentlang}&region=${contentregion}&h=${btoa(Date.now())}`).then((res) => res.text()),
curly
.get(`${this.config.tubeApi}video?v=${v}`, {
fetchWithRetry(`${this.config.invapi}/comments/${v}?hl=${contentlang}&region=${contentregion}&h=${btoa(Date.now())}`).then(res => res.text()),
fetchWithRetry(`${this.config.invapi}/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}`),
})
.then((res) => {
}).then(res => {
const json = toJson(res.data);
const video = this.getJson(json);
return { json, video };
}),
]);
const comments = await this.getJson(invComments);
const vid = await this.getJson(videoInfo);
const comments = this.getJson(invComments);
const vid = this.getJson(videoInfo);
const { json, video } = videoData;
var channel_uploads = { };
if (f == "true") {
channel_uploads = await fetch(
`${this.config.invapi}/channels/${vid.authorId}?hl=${contentlang}&region=${contentregion}`
);
var p = this.getJson(await channel_uploads.text());
let p = {};
if (f === "true") {
const uploads = await fetchWithRetry(`${this.config.invapi}/channels/${vid.authorId}?hl=${contentlang}&region=${contentregion}`);
p = this.getJson(await uploads.text());
}
if (!vid) {
console.log(
`Sorry nya, we couldn't find any information about that video qwq`
);
console.log(`Sorry nya, we couldn't find any information about that video qwq`);
}
if (this.checkUnexistingObject(vid)) {
const fe = await getdislikes(v);
try {
const headers = {};
// Store result in cache
this.cache[v] = {
result: {
json: json?.video,
@ -151,59 +109,38 @@ class InnerTubePokeVidious {
engagement: fe.engagement,
wiki: "",
desc: "",
color: await getColors(
`https://i.ytimg.com/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}`
).then((colors) => colors[1].hex()),
color: await getColors(`https://i.ytimg.com/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}`).then(colors => colors[1].hex()),
},
timestamp: Date.now(),
};
return this.cache[v].result;
}
} catch (error) {
this.initError("Error getting video", error);
}
}
} catch {
}
}
/**
* Check if a video ID is valid.
* @param {string} v - Video ID.
* @returns {boolean} True if the video ID is valid, false otherwise.
*/
isvalidvideo(v) {
if (v != "assets" && v != "cdn-cgi" && v != "404") {
const regex = new RegExp("^([a-zA-Z0-9_-]{11})");
const isMatch = regex.test(v);
return isMatch;
} else {
return /^([a-zA-Z0-9_-]{11})/.test(v);
}
return false;
}
}
/**
* Initialize an error.
* @param {string} args - Error message.
* @param {Error} error - Error object.
*/
initError(args, error) {
console.error("[LIBPT CORE ERROR]" + args, error);
console.error("[LIBPT CORE ERROR] " + args, error);
}
}
// Create an instance of InnerTubePokeVidious with the provided config
const pokeTubeApiCore = new InnerTubePokeVidious({
tubeApi: "https://inner-api.poketube.fun/api/",
invapi: "https://invid-api.poketube.fun/bHj665PpYhUdPWuKPfZuQGoX/api/v1",
invapi_alt: config.proxylocation === "EU" ? "https://invid-api.poketube.fun/api/v1" : "https://iv.ggtyler.dev/api/v1",
dislikes: "https://returnyoutubedislikeapi.com/votes?videoId=",
t_url: "https://t.poketube.fun/",
useragent: config.useragent,
});
module.exports = pokeTubeApiCore;