mirror of
https://codeberg.org/ashley/poke
synced 2025-06-19 20:12:10 +00:00
Compare commits
75 Commits
906f7b237e
...
dcf3b20fac
Author | SHA1 | Date | |
---|---|---|---|
![]() |
dcf3b20fac | ||
![]() |
b91128ff11 | ||
![]() |
46abf16976 | ||
![]() |
f9d434903d | ||
![]() |
dd5aea5304 | ||
![]() |
84b92ae3ac | ||
![]() |
f05f3e5b3a | ||
![]() |
b4d7b3da11 | ||
![]() |
bb1d09ea20 | ||
![]() |
d708f964eb | ||
![]() |
e4da5d48d4 | ||
![]() |
ac979c3bdc | ||
![]() |
f31ff98a0b | ||
![]() |
cc3922ad0e | ||
![]() |
6e1aecaeb4 | ||
![]() |
c9e8b8f85d | ||
![]() |
99f4d03bbb | ||
![]() |
efd3c59df7 | ||
![]() |
a5a18ba383 | ||
![]() |
c531678a18 | ||
![]() |
c9bd527527 | ||
![]() |
495367eace | ||
![]() |
547f68c882 | ||
![]() |
6268bdebfb | ||
![]() |
7527e49c9c | ||
![]() |
7125ecc36e | ||
![]() |
4058e8ef11 | ||
![]() |
0527a9e52f | ||
![]() |
230d371ced | ||
![]() |
4a8070e65c | ||
![]() |
556285a8d1 | ||
![]() |
3076fb9393 | ||
![]() |
777e8522b2 | ||
![]() |
efe0f7d758 | ||
![]() |
38094732ba | ||
![]() |
b8ce39698a | ||
![]() |
4519933c9e | ||
![]() |
18635eca02 | ||
![]() |
2202193d23 | ||
![]() |
b1de0358a7 | ||
![]() |
739d64f684 | ||
![]() |
d539547fd3 | ||
![]() |
c5e67b7f05 | ||
![]() |
d31253551c | ||
![]() |
0f40a4a152 | ||
![]() |
6e627b48a7 | ||
![]() |
704b7bc806 | ||
![]() |
f77d5e0260 | ||
![]() |
5ab4cc30a5 | ||
![]() |
afa738f8c2 | ||
![]() |
3f19854798 | ||
![]() |
6801889f64 | ||
![]() |
ce5428eccb | ||
![]() |
3f66e88dae | ||
![]() |
7ef352f3cb | ||
![]() |
38871bba36 | ||
![]() |
e755ef3f4c | ||
![]() |
64433797f3 | ||
![]() |
3f69953875 | ||
![]() |
b69b2a590e | ||
![]() |
3558b47301 | ||
![]() |
acef288683 | ||
![]() |
27becd05a6 | ||
![]() |
0347a9ab94 | ||
![]() |
e775e617ed | ||
![]() |
59dd95fa39 | ||
![]() |
fd1f3ea864 | ||
![]() |
310ffb643c | ||
![]() |
4bf687b4a3 | ||
![]() |
4acf840d80 | ||
![]() |
4b33b38e1f | ||
![]() |
7188bfdf03 | ||
![]() |
440431abbd | ||
![]() |
172a7175ec | ||
![]() |
b5e09f60eb |
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@ yarn.lock
|
||||
package-lock.json
|
||||
.env
|
||||
json.sqlite
|
||||
config.json
|
@ -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",
|
34
css/maps.js
34
css/maps.js
@ -1,33 +1 @@
|
||||
var bbox = "?bbox=-165.76171875000003%2C-3.864254615721396%2C30.410156250000004%2C72.44879155730672&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)})()};);
|
2596
html/gamehub.ejs
2596
html/gamehub.ejs
File diff suppressed because it is too large
Load Diff
@ -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>" }
|
||||
@ -187,10 +190,7 @@ const randomFeatures = features.sort(() => 0.5 - Math.random()).slice(0, 3);
|
||||
secondary_icon='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M524.5 69.8a1.5 1.5 0 0 0 -.8-.7A485.1 485.1 0 0 0 404.1 32a1.8 1.8 0 0 0 -1.9 .9 337.5 337.5 0 0 0 -14.9 30.6 447.8 447.8 0 0 0 -134.4 0 309.5 309.5 0 0 0 -15.1-30.6 1.9 1.9 0 0 0 -1.9-.9A483.7 483.7 0 0 0 116.1 69.1a1.7 1.7 0 0 0 -.8 .7C39.1 183.7 18.2 294.7 28.4 404.4a2 2 0 0 0 .8 1.4A487.7 487.7 0 0 0 176 479.9a1.9 1.9 0 0 0 2.1-.7A348.2 348.2 0 0 0 208.1 430.4a1.9 1.9 0 0 0 -1-2.6 321.2 321.2 0 0 1 -45.9-21.9 1.9 1.9 0 0 1 -.2-3.1c3.1-2.3 6.2-4.7 9.1-7.1a1.8 1.8 0 0 1 1.9-.3c96.2 43.9 200.4 43.9 295.5 0a1.8 1.8 0 0 1 1.9 .2c2.9 2.4 6 4.9 9.1 7.2a1.9 1.9 0 0 1 -.2 3.1 301.4 301.4 0 0 1 -45.9 21.8 1.9 1.9 0 0 0 -1 2.6 391.1 391.1 0 0 0 30 48.8 1.9 1.9 0 0 0 2.1 .7A486 486 0 0 0 610.7 405.7a1.9 1.9 0 0 0 .8-1.4C623.7 277.6 590.9 167.5 524.5 69.8zM222.5 337.6c-29 0-52.8-26.6-52.8-59.2S193.1 219.1 222.5 219.1c29.7 0 53.3 26.8 52.8 59.2C275.3 311 251.9 337.6 222.5 337.6zm195.4 0c-29 0-52.8-26.6-52.8-59.2S388.4 219.1 417.9 219.1c29.7 0 53.3 26.8 52.8 59.2C470.7 311 447.5 337.6 417.9 337.6z"/></svg>',
|
||||
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',
|
||||
|
@ -1,109 +1,146 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<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>
|
||||
body {
|
||||
margin: auto;
|
||||
background: #111111;
|
||||
color: white;
|
||||
font-family: arial;
|
||||
max-width: 600px;
|
||||
}
|
||||
body::before {
|
||||
background: linear-gradient(0deg, rgba(115, 32, 67, 1), rgba(17, 17, 17, 1));
|
||||
background-repeat: no-repeat;
|
||||
content: "";
|
||||
position: fixed;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: -1;
|
||||
pointer-events: none;
|
||||
transition: 1s height;
|
||||
}
|
||||
<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" />
|
||||
<link href="/css/yt-ukraine.svg?v=3" rel="icon" />
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<style>
|
||||
body {
|
||||
margin: auto;
|
||||
background: #111111;
|
||||
color: white;
|
||||
font-family: arial;
|
||||
max-width: 600px;
|
||||
}
|
||||
body::before {
|
||||
background: linear-gradient(0deg, rgba(115, 32, 67, 1), rgba(17, 17, 17, 1));
|
||||
background-repeat: no-repeat;
|
||||
content: "";
|
||||
position: fixed;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: -1;
|
||||
pointer-events: none;
|
||||
transition: 1s height;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 42px;
|
||||
}
|
||||
h2 {
|
||||
font-size: 42px;
|
||||
}
|
||||
|
||||
p#abstract {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 500px;
|
||||
margin: 0px;
|
||||
font-weight: bold;
|
||||
opacity: 0.005;
|
||||
pointer-events: none;
|
||||
transition: 1s transform;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 790px) {
|
||||
p#abstract {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 500px;
|
||||
margin: 0px;
|
||||
font-weight: bold;
|
||||
opacity: 0.005;
|
||||
pointer-events: none;
|
||||
transition: 1s transform;
|
||||
transform: translate(-50%, -50%) rotate(90deg) !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 790px) {
|
||||
p#abstract {
|
||||
transform: translate(-50%, -50%) rotate(90deg) !important;
|
||||
.error {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
text-align: center;
|
||||
cursor: default;
|
||||
max-width: 600px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.error-footer {
|
||||
position: fixed;
|
||||
bottom: 24px;
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
text-align: center;
|
||||
}
|
||||
.error-footer a {
|
||||
color: #ac8fa5;
|
||||
text-decoration: none;
|
||||
margin: 0px 12px;
|
||||
}
|
||||
.error-footer a:hover {
|
||||
color: #d69cc8;
|
||||
}
|
||||
.countdown {
|
||||
margin-top: 16px;
|
||||
color: #ccc;
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<% 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...";
|
||||
}
|
||||
|
||||
.error {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
text-align: center;
|
||||
cursor: default;
|
||||
max-width: 600px;
|
||||
width: 100%;
|
||||
if (seconds <= 0) {
|
||||
location.reload();
|
||||
} else {
|
||||
seconds--;
|
||||
setTimeout(updateCountdown, 1000);
|
||||
}
|
||||
|
||||
.error-footer {
|
||||
position: fixed;
|
||||
bottom: 24px;
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
text-align: center;
|
||||
}
|
||||
.error-footer a {
|
||||
color: #ac8fa5;
|
||||
text-decoration: none;
|
||||
margin: 0px 12px;
|
||||
}
|
||||
.error-footer a:hover {
|
||||
color: #d69cc8;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<% if (description == "This helps protect our community. Learn more (TRYING AGAIN....)") { %>
|
||||
|
||||
}
|
||||
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....)") { %>
|
||||
<p id="abstract">404</p>
|
||||
<% } else { %>
|
||||
<p id="abstract">404</p>
|
||||
<% } %>
|
||||
|
||||
<% } %>
|
||||
|
||||
<div class="error">
|
||||
<h2><%=error%></h2>
|
||||
<p><%=description%></p>
|
||||
</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....)") { %>
|
||||
<div class="error">
|
||||
<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 === RESTART_MSG) { %>
|
||||
<a href="https://github.com/iv-org/invidious/issues">See Invidious issues</a>
|
||||
<a href="">Refresh Page</a>
|
||||
<% } %>
|
||||
</div>
|
||||
</body>
|
||||
<% } %>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
176
html/map.ejs
176
html/map.ejs
@ -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>
|
||||
|
@ -11,8 +11,7 @@
|
||||
<% 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>
|
||||
<% }%>
|
||||
</div>
|
||||
|
||||
|
588
html/search.ejs
588
html/search.ejs
@ -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,58 +541,138 @@ function getCurrentYear() {
|
||||
}
|
||||
|
||||
function getTimeInTimezone(location) {
|
||||
const timezones = {
|
||||
"california": "America/Los_Angeles",
|
||||
"new york": "America/New_York",
|
||||
"chicago": "America/Chicago",
|
||||
"denver": "America/Denver",
|
||||
"phoenix": "America/Phoenix",
|
||||
"anchorage": "America/Anchorage",
|
||||
"honolulu": "Pacific/Honolulu",
|
||||
"london": "Europe/London",
|
||||
"paris": "Europe/Paris",
|
||||
"berlin": "Europe/Berlin",
|
||||
"madrid": "Europe/Madrid",
|
||||
"rome": "Europe/Rome",
|
||||
"moscow": "Europe/Moscow",
|
||||
"athens": "Europe/Athens",
|
||||
"sydney": "Australia/Sydney",
|
||||
"melbourne": "Australia/Melbourne",
|
||||
"brisbane": "Australia/Brisbane",
|
||||
"perth": "Australia/Perth",
|
||||
"tokyo": "Asia/Tokyo",
|
||||
"osaka": "Asia/Osaka",
|
||||
"seoul": "Asia/Seoul",
|
||||
"beijing": "Asia/Shanghai",
|
||||
"shanghai": "Asia/Shanghai",
|
||||
"hong kong": "Asia/Hong_Kong",
|
||||
"taipei": "Asia/Taipei",
|
||||
"bangkok": "Asia/Bangkok",
|
||||
"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",
|
||||
"johannesburg": "Africa/Johannesburg",
|
||||
"cairo": "Africa/Cairo",
|
||||
"nairobi": "Africa/Nairobi",
|
||||
"lagos": "Africa/Lagos",
|
||||
"algiers": "Africa/Algiers",
|
||||
"casablanca": "Africa/Casablanca",
|
||||
"lisbon": "Europe/Lisbon",
|
||||
"dublin": "Europe/Dublin",
|
||||
"zurich": "Europe/Zurich",
|
||||
"vienna": "Europe/Vienna",
|
||||
"stockholm": "Europe/Stockholm",
|
||||
"oslo": "Europe/Oslo",
|
||||
"helsinki": "Europe/Helsinki"
|
||||
};
|
||||
const tzMap = {
|
||||
"california": "America/Los_Angeles",
|
||||
"new york": "America/New_York",
|
||||
"chicago": "America/Chicago",
|
||||
"denver": "America/Denver",
|
||||
"phoenix": "America/Phoenix",
|
||||
"anchorage": "America/Anchorage",
|
||||
"honolulu": "Pacific/Honolulu",
|
||||
"london": "Europe/London",
|
||||
"paris": "Europe/Paris",
|
||||
"berlin": "Europe/Berlin",
|
||||
"madrid": "Europe/Madrid",
|
||||
"rome": "Europe/Rome",
|
||||
"moscow": "Europe/Moscow",
|
||||
"athens": "Europe/Athens",
|
||||
"sydney": "Australia/Sydney",
|
||||
"melbourne": "Australia/Melbourne",
|
||||
"brisbane": "Australia/Brisbane",
|
||||
"perth": "Australia/Perth",
|
||||
"tokyo": "Asia/Tokyo",
|
||||
"osaka": "Asia/Osaka",
|
||||
"seoul": "Asia/Seoul",
|
||||
"beijing": "Asia/Shanghai",
|
||||
"shanghai": "Asia/Shanghai",
|
||||
"hong kong": "Asia/Hong_Kong",
|
||||
"taipei": "Asia/Taipei",
|
||||
"bangkok": "Asia/Bangkok",
|
||||
"jakarta": "Asia/Jakarta",
|
||||
"delhi": "Asia/Kolkata",
|
||||
"mumbai": "Asia/Kolkata",
|
||||
"karachi": "Asia/Karachi",
|
||||
"dubai": "Asia/Dubai",
|
||||
"abu dhabi": "Asia/Dubai",
|
||||
"riyadh": "Asia/Riyadh",
|
||||
"johannesburg": "Africa/Johannesburg",
|
||||
"cairo": "Africa/Cairo",
|
||||
"nairobi": "Africa/Nairobi",
|
||||
"lagos": "Africa/Lagos",
|
||||
"algiers": "Africa/Algiers",
|
||||
"casablanca": "Africa/Casablanca",
|
||||
"lisbon": "Europe/Lisbon",
|
||||
"dublin": "Europe/Dublin",
|
||||
"zurich": "Europe/Zurich",
|
||||
"vienna": "Europe/Vienna",
|
||||
"stockholm": "Europe/Stockholm",
|
||||
"oslo": "Europe/Oslo",
|
||||
"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 = [
|
||||
"You’re 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—you’ve got this!",
|
||||
"Don’t 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,16 +878,69 @@ 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?'",
|
||||
@ -653,31 +966,110 @@ 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;">
|
||||
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 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="PokeIntellagance!" class="fa-light fa-sparkles"></i>
|
||||
</h2>
|
||||
<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) { %>
|
||||
|
||||
<% } %>
|
||||
|
||||
<% 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>
|
||||
<span style="margin-bottom: 3em; text-align: left !important; margin-right: 7em; white-space: pre-wrap; word-break: break-word;">
|
||||
POKE doesn’t need "AI." There’s 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. It’s 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 doesn’t come from chasing whatever big tech wants to sell you on. It’s 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>
|
||||
</div>
|
||||
<% } %>
|
||||
|
||||
|
||||
<!-- self harm -->
|
||||
<%
|
||||
@ -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>
|
||||
|
@ -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' },
|
||||
@ -278,71 +112,285 @@
|
||||
{ code: 'yi', name: 'Yiddish' },
|
||||
{ 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">
|
||||
<select name="from_language" id="from_language">
|
||||
<% languageOptions.forEach(language => { %>
|
||||
<option value="<%= language.code %>" <%= language.code === (from_language || 'autodetect') ? 'selected' : '' %>>
|
||||
<%= language.name %>
|
||||
</option>
|
||||
<% }); %>
|
||||
</select>
|
||||
|
||||
<select name="to_language" id="to_language">
|
||||
<% languageOptions.slice(1).forEach(language => { %>
|
||||
<option value="<%= language.code %>" <%= language.code === to_language ? 'selected' : '' %>>
|
||||
<%= language.name %>
|
||||
</option>
|
||||
<% }); %>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- text boxes -->
|
||||
<div class="wrap">
|
||||
<div class="item-wrapper">
|
||||
<textarea autofocus class="item" id="input" name="input" dir="auto" placeholder="<%- text %>">
|
||||
<%- text %>
|
||||
</textarea>
|
||||
</div>
|
||||
|
||||
<div class="item-wrapper">
|
||||
<textarea id="output" class="translation item" dir="auto" placeholder="Translation" readonly>
|
||||
<%- translation %>
|
||||
</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="center">
|
||||
<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();
|
||||
}
|
||||
});
|
||||
|
||||
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";
|
||||
});
|
||||
</script>
|
||||
<script src="/static/custom-css.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
]; %>
|
||||
|
||||
<!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(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(lang => { %>
|
||||
<option value="<%= lang.code %>" <%= lang.code===to_language?'selected':''%>>
|
||||
<%= lang.name %>
|
||||
</option>
|
||||
<% }); %>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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="panel output">
|
||||
<label for="output">Translation</label>
|
||||
<textarea id="output" readonly placeholder="Translated text…"><%= translation %></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<button type="submit">Translate :3</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(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();
|
||||
});
|
||||
|
||||
// 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>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -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..";
|
||||
}
|
||||
%>
|
||||
|
||||
|
@ -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="avc1.64001F, mp4a.40.2"" 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="avc1.64001F, mp4a.40.2"" label="hd720" selected="true">
|
||||
<% } %>
|
||||
<% if (qua === "medium") { %>
|
||||
<source src="<%=u%>/latest_version?id=<%=inv_vid.videoId%>&itag=18&local=true" type="video/mp4; codecs="avc1.64001F, mp4a.40.2"" 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="avc1.64001F, mp4a.40.2"" 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,13 +1838,7 @@ 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) { %>
|
||||
|
||||
<div class="tags rec" style="margin-left:auto">
|
||||
@ -2575,13 +2570,7 @@ 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="avc1.64001F, mp4a.40.2"" 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") %>
|
||||
|
||||
|
||||
|
@ -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"
|
||||
|
@ -23,118 +23,114 @@ var ping = require("ping");
|
||||
|
||||
const sha384 = modules.hash;
|
||||
|
||||
|
||||
const splash = [
|
||||
"Woke!",
|
||||
"Gay gay homosexaul gay!",
|
||||
"free Palestine!",
|
||||
"free software!",
|
||||
"im... stuff!",
|
||||
"frick capitalism!",
|
||||
"still calling it twitter btw!",
|
||||
"boop!",
|
||||
"no way!",
|
||||
"traaaa rightssss!",
|
||||
"XD!",
|
||||
"nya!",
|
||||
"say gex!",
|
||||
"ur valid :3",
|
||||
"gay space communism!",
|
||||
"doesnt have AI!",
|
||||
"no web3!",
|
||||
"keemstar is a bald ___!",
|
||||
"No One calls it 'X'! ",
|
||||
"Eat the rich!",
|
||||
"Does Not include Nazis!",
|
||||
"also try piped!",
|
||||
"not alt-right!",
|
||||
"coke zero > coke classic!",
|
||||
"poke & chill!",
|
||||
"can play HD!",
|
||||
"also try invidious!",
|
||||
"also try vencord!",
|
||||
"rms <3!",
|
||||
"du hast",
|
||||
"can u belive no one bought this?",
|
||||
"reee",
|
||||
"1.000.000€!",
|
||||
"pika!",
|
||||
"fsf.org",
|
||||
"ssfffssfssfffaassssfsdf!",
|
||||
"𝓯𝓻𝓮𝓪𝓴𝔂poke",
|
||||
"they not like us!",
|
||||
"to pimp a butterfly!",
|
||||
"king kunta!",
|
||||
"HUMBLE.",
|
||||
"can you save my hds?",
|
||||
"sahlo folina!",
|
||||
"we come for you!",
|
||||
"no chances!",
|
||||
"dema dont control us!",
|
||||
"i see your problem is, your proctologist",
|
||||
"got both hands on your shoulder",
|
||||
"while ur bottomless!",
|
||||
"you should bounce bounce bounce man!",
|
||||
"its lavish!",
|
||||
"im vibin, vibin!",
|
||||
"i would swim the paladin strait",
|
||||
"hello clancy!",
|
||||
"NO NOT ME,ITS FOR A FRIEND",
|
||||
"im fairly local!",
|
||||
"i dont wanna go like this!",
|
||||
"east is up!",
|
||||
"not done, josh dun!",
|
||||
"your the judge, oh no!",
|
||||
"I dont wanna backslide",
|
||||
"welcome back to trench!",
|
||||
"sai is propaganda!",
|
||||
" •|i|• Ø i+! ].[",
|
||||
"stay alive! |-/",
|
||||
"the few, the proud, the Emotional!",
|
||||
"ill morph into someone else",
|
||||
"still alive",
|
||||
"follow the torches",
|
||||
"i created this world!",
|
||||
"to feel some control!",
|
||||
"destory it if i want!",
|
||||
"o7 keons",
|
||||
"at least let me clean my room",
|
||||
"100+ stars on gh!",
|
||||
"let the vibe slide over me!",
|
||||
"sip a capri sun like its don peregon",
|
||||
"now even gayer!",
|
||||
"its joever..",
|
||||
"lesbiam,,,",
|
||||
"poke!!!",
|
||||
"discord.poketube.fun!",
|
||||
"women are pretty!",
|
||||
"men are handsome!",
|
||||
"enbys are cute!",
|
||||
"you are cute :3",
|
||||
"read if cute!",
|
||||
"this shit awesome!",
|
||||
"ur pawsome!",
|
||||
"meows at u",
|
||||
"hai i am gay",
|
||||
"yay, GEX!",
|
||||
"say gex..,,",
|
||||
"wha if we um erm",
|
||||
"turkey is literally 1984!",
|
||||
"turkey is literally 1984!",
|
||||
"turkey is literally 1984!",
|
||||
"turkey is literally 1984!",
|
||||
"turkey is literally 1984!",
|
||||
"turkey is literally 1984!",
|
||||
"awesome screen!",
|
||||
"awesome camera!",
|
||||
"long lasting battery life",
|
||||
"stallmansupport.org!!!",
|
||||
"does include nya~!!!",
|
||||
"actually stable! :3",
|
||||
]
|
||||
|
||||
|
||||
|
||||
"Woke!",
|
||||
"Gay gay homosexaul gay!",
|
||||
"free Palestine!",
|
||||
"free software!",
|
||||
"im... stuff!",
|
||||
"frick capitalism!",
|
||||
"still calling it twitter btw!",
|
||||
"boop!",
|
||||
"no way!",
|
||||
"traaaa rightssss!",
|
||||
"XD!",
|
||||
"nya!",
|
||||
"say gex!",
|
||||
"ur valid :3",
|
||||
"gay space communism!",
|
||||
"doesnt have AI!",
|
||||
"no web3!",
|
||||
"keemstar is a bald ___!",
|
||||
"No One calls it 'X'! ",
|
||||
"Eat the rich!",
|
||||
"Does Not include Nazis!",
|
||||
"also try piped!",
|
||||
"not alt-right!",
|
||||
"coke zero > coke classic!",
|
||||
"poke & chill!",
|
||||
"can play HD!",
|
||||
"also try invidious!",
|
||||
"also try vencord!",
|
||||
"rms <3!",
|
||||
"du hast",
|
||||
"can u belive no one bought this?",
|
||||
"reee",
|
||||
"1.000.000€!",
|
||||
"pika!",
|
||||
"fsf.org",
|
||||
"ssfffssfssfffaassssfsdf!",
|
||||
"𝓯𝓻𝓮𝓪𝓴𝔂poke",
|
||||
"they not like us!",
|
||||
"to pimp a butterfly!",
|
||||
"king kunta!",
|
||||
"HUMBLE.",
|
||||
"can you save my hds?",
|
||||
"sahlo folina!",
|
||||
"we come for you!",
|
||||
"no chances!",
|
||||
"dema dont control us!",
|
||||
"i see your problem is, your proctologist",
|
||||
"got both hands on your shoulder",
|
||||
"while ur bottomless!",
|
||||
"you should bounce bounce bounce man!",
|
||||
"its lavish!",
|
||||
"im vibin, vibin!",
|
||||
"i would swim the paladin strait",
|
||||
"hello clancy!",
|
||||
"NO NOT ME,ITS FOR A FRIEND",
|
||||
"im fairly local!",
|
||||
"i dont wanna go like this!",
|
||||
"east is up!",
|
||||
"not done, josh dun!",
|
||||
"your the judge, oh no!",
|
||||
"I dont wanna backslide",
|
||||
"welcome back to trench!",
|
||||
"sai is propaganda!",
|
||||
" •|i|• Ø i+! ].[",
|
||||
"stay alive! |-/",
|
||||
"the few, the proud, the Emotional!",
|
||||
"ill morph into someone else",
|
||||
"still alive",
|
||||
"follow the torches",
|
||||
"i created this world!",
|
||||
"to feel some control!",
|
||||
"destory it if i want!",
|
||||
"o7 keons",
|
||||
"at least let me clean my room",
|
||||
"100+ stars on gh!",
|
||||
"let the vibe slide over me!",
|
||||
"sip a capri sun like its don peregon",
|
||||
"now even gayer!",
|
||||
"its joever..",
|
||||
"lesbiam,,,",
|
||||
"poke!!!",
|
||||
"discord.poketube.fun!",
|
||||
"women are pretty!",
|
||||
"men are handsome!",
|
||||
"enbys are cute!",
|
||||
"you are cute :3",
|
||||
"read if cute!",
|
||||
"this shit awesome!",
|
||||
"ur pawsome!",
|
||||
"meows at u",
|
||||
"hai i am gay",
|
||||
"yay, GEX!",
|
||||
"say gex..,,",
|
||||
"wha if we um erm",
|
||||
"turkey is literally 1984!",
|
||||
"turkey is literally 1984!",
|
||||
"turkey is literally 1984!",
|
||||
"turkey is literally 1984!",
|
||||
"turkey is literally 1984!",
|
||||
"turkey is literally 1984!",
|
||||
"awesome screen!",
|
||||
"awesome camera!",
|
||||
"long lasting battery life",
|
||||
"stallmansupport.org!!!",
|
||||
"does include nya~!!!",
|
||||
"actually stable! :3",
|
||||
];
|
||||
|
||||
function getJson(str) {
|
||||
try {
|
||||
@ -146,20 +142,23 @@ function getJson(str) {
|
||||
|
||||
module.exports = function (app, config, renderTemplate) {
|
||||
app.get("/app", async function (req, res) {
|
||||
const { fetch } = await import("undici");
|
||||
const { fetch } = await import("undici");
|
||||
|
||||
let tab = "";
|
||||
if (req.query.tab) {
|
||||
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,14 +221,14 @@ 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
|
||||
});
|
||||
isOldWindows,
|
||||
random,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return rendermainpage();
|
||||
});
|
||||
};
|
||||
};
|
||||
|
@ -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");
|
||||
|
@ -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}`
|
||||
|
||||
let f = await modules.fetch(url + `?cachefixer=${btoa(Date.now())}`, {
|
||||
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,31 +58,22 @@ 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;
|
||||
@ -101,170 +81,133 @@ app.get("/avatars/:v", async function (req, res) {
|
||||
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);
|
||||
});
|
||||
|
||||
app.get("/api/subtitles", async (req, res) => {
|
||||
const { fetch } = await import("undici");
|
||||
|
||||
|
||||
const id = req.query.v;
|
||||
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);
|
||||
} catch {}
|
||||
});
|
||||
|
||||
app.get("/api/getEngagementData", async (req, res) => {
|
||||
const { fetch } = await import("undici");
|
||||
|
||||
const id = req.query.v;
|
||||
|
||||
try {
|
||||
if (id) {
|
||||
const apiUrl = `https://ryd-proxy.kavin.rocks/votes/${id}&hash=d0550b6e28c8f93533a569c314d5b4e2`;
|
||||
|
||||
const response = await fetch(apiUrl);
|
||||
|
||||
if (response.status === 400) {
|
||||
const error = await response.json();
|
||||
return res.status(400).send(error);
|
||||
}
|
||||
|
||||
const engagement = await response.json();
|
||||
|
||||
const likes = parseInt(engagement.likes) || 0;
|
||||
const dislikes = parseInt(engagement.dislikes) || 0;
|
||||
const total = likes + dislikes;
|
||||
|
||||
const likePercentage = total > 0 ? ((likes / total) * 100).toFixed(2) : 0;
|
||||
const dislikePercentage = total > 0 ? ((dislikes / total) * 100).toFixed(2) : 0;
|
||||
|
||||
const getLikePercentageColor = (percentage) => {
|
||||
if (percentage >= 80) {
|
||||
return "green";
|
||||
} else if (percentage >= 50) {
|
||||
return "orange";
|
||||
} else {
|
||||
return "red";
|
||||
}
|
||||
};
|
||||
|
||||
const getDislikePercentageColor = (percentage) => {
|
||||
if (percentage >= 50) {
|
||||
return "red";
|
||||
} else if (percentage >= 20) {
|
||||
return "orange";
|
||||
} else {
|
||||
return "green";
|
||||
}
|
||||
};
|
||||
|
||||
const likeColor = getLikePercentageColor(likePercentage);
|
||||
const dislikeColor = getDislikePercentageColor(dislikePercentage);
|
||||
|
||||
const userScore = (
|
||||
parseFloat(likePercentage) -
|
||||
parseFloat(dislikePercentage) / 2
|
||||
).toFixed(2);
|
||||
|
||||
const getUserScoreLabel = (score) => {
|
||||
if (score >= 98) {
|
||||
return "Masterpiece Video";
|
||||
} else if (score >= 80) {
|
||||
return "Overwhelmingly Positive";
|
||||
} else if (score >= 60) {
|
||||
return "Positive";
|
||||
} else if (score >= 40) {
|
||||
return "Mixed";
|
||||
} else if (score >= 20) {
|
||||
return "Negative";
|
||||
} else {
|
||||
return "Overwhelmingly Negative";
|
||||
}
|
||||
};
|
||||
|
||||
const userScoreLabel = getUserScoreLabel(userScore);
|
||||
const userScoreColor =
|
||||
userScore >= 80 ? "green" : userScore >= 50 ? "orange" : "red";
|
||||
|
||||
const respon = {
|
||||
like_count: likes,
|
||||
dislike_count: dislikes,
|
||||
rating: engagement.rating,
|
||||
userScore: {
|
||||
label: userScoreLabel,
|
||||
score: userScore,
|
||||
color: userScoreColor,
|
||||
},
|
||||
engagement: {
|
||||
likeColor: likeColor,
|
||||
dislikeColor: dislikeColor,
|
||||
percentage: {
|
||||
likePercentage: `${likePercentage}%`,
|
||||
dislikePercentage: `${dislikePercentage}%`,
|
||||
},
|
||||
},
|
||||
ReturnYouTubeDislikesApiRawResponse: engagement,
|
||||
};
|
||||
|
||||
res.send(respon);
|
||||
} else {
|
||||
res.status(400).json("pls gib ID :3");
|
||||
}
|
||||
} 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(/&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) => {
|
||||
app.get("/api/getEngagementData", 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`;
|
||||
if (id) {
|
||||
const apiUrl = `https://ryd-proxy.kavin.rocks/votes/${id}&hash=d0550b6e28c8f93533a569c314d5b4e2`;
|
||||
|
||||
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}`;
|
||||
const response = await fetch(apiUrl, {
|
||||
headers: headers,
|
||||
});
|
||||
|
||||
res.send(body);
|
||||
} catch {}
|
||||
});
|
||||
if (response.status === 400) {
|
||||
const error = await response.json();
|
||||
return res.status(400).send(error);
|
||||
}
|
||||
|
||||
const engagement = await response.json();
|
||||
|
||||
const likes = parseInt(engagement.likes) || 0;
|
||||
const dislikes = parseInt(engagement.dislikes) || 0;
|
||||
const total = likes + dislikes;
|
||||
|
||||
const likePercentage = total > 0 ? ((likes / total) * 100).toFixed(2) : 0;
|
||||
const dislikePercentage = total > 0 ? ((dislikes / total) * 100).toFixed(2) : 0;
|
||||
|
||||
const getLikePercentageColor = (percentage) => {
|
||||
if (percentage >= 80) {
|
||||
return "green";
|
||||
} else if (percentage >= 50) {
|
||||
return "orange";
|
||||
} else {
|
||||
return "red";
|
||||
}
|
||||
};
|
||||
|
||||
const getDislikePercentageColor = (percentage) => {
|
||||
if (percentage >= 50) {
|
||||
return "red";
|
||||
} else if (percentage >= 20) {
|
||||
return "orange";
|
||||
} else {
|
||||
return "green";
|
||||
}
|
||||
};
|
||||
|
||||
const likeColor = getLikePercentageColor(likePercentage);
|
||||
const dislikeColor = getDislikePercentageColor(dislikePercentage);
|
||||
|
||||
const userScore = (
|
||||
parseFloat(likePercentage) -
|
||||
parseFloat(dislikePercentage) / 2
|
||||
).toFixed(2);
|
||||
|
||||
const getUserScoreLabel = (score) => {
|
||||
if (score >= 98) {
|
||||
return "Masterpiece Video";
|
||||
} else if (score >= 80) {
|
||||
return "Overwhelmingly Positive";
|
||||
} else if (score >= 60) {
|
||||
return "Positive";
|
||||
} else if (score >= 40) {
|
||||
return "Mixed";
|
||||
} else if (score >= 20) {
|
||||
return "Negative";
|
||||
} else {
|
||||
return "Overwhelmingly Negative";
|
||||
}
|
||||
};
|
||||
|
||||
const userScoreLabel = getUserScoreLabel(userScore);
|
||||
const userScoreColor =
|
||||
userScore >= 80 ? "green" : userScore >= 50 ? "orange" : "red";
|
||||
|
||||
const respon = {
|
||||
like_count: likes,
|
||||
dislike_count: dislikes,
|
||||
rating: engagement.rating,
|
||||
userScore: {
|
||||
label: userScoreLabel,
|
||||
score: userScore,
|
||||
color: userScoreColor,
|
||||
},
|
||||
engagement: {
|
||||
likeColor: likeColor,
|
||||
dislikeColor: dislikeColor,
|
||||
percentage: {
|
||||
likePercentage: `${likePercentage}%`,
|
||||
dislikePercentage: `${dislikePercentage}%`,
|
||||
},
|
||||
},
|
||||
ReturnYouTubeDislikesApiRawResponse: engagement,
|
||||
};
|
||||
|
||||
res.send(respon);
|
||||
} else {
|
||||
res.status(400).json("pls gib ID :3");
|
||||
}
|
||||
} catch (error) {
|
||||
res.status(500).json("whoops (error 500) >~<");
|
||||
}
|
||||
});
|
||||
|
||||
app.get("/feeds/videos.xml", async (req, res) => {
|
||||
const id = req.query.channel_id;
|
||||
@ -273,25 +216,25 @@ 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);
|
||||
});
|
||||
|
||||
app.get("/api/manifest/dash/id/:id", async (req, res) => {
|
||||
app.get("/api/manifest/dash/id/:id", async (req, res) => {
|
||||
const id = req.params.id;
|
||||
|
||||
let url = `https://invid-api.poketube.fun/bHj665PpYhUdPWuKPfZuQGoX/api/manifest/dash/id/${id}`;
|
||||
|
||||
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,38 +257,41 @@ 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));
|
||||
|
||||
const cpus = os.cpus();
|
||||
const totalMemory = os.totalmem() / (1024 * 1024 * 1024);
|
||||
const roundedMemory = totalMemory.toFixed(2);
|
||||
|
||||
execSync('git rev-list HEAD -n 1 --abbrev-commit', (error, stdout, stderr) => {
|
||||
if (error || stderr) {
|
||||
console.error(`Error executing command: ${error || stderr}`);
|
||||
return;
|
||||
}
|
||||
const cpus = os.cpus();
|
||||
const totalMemory = os.totalmem() / (1024 * 1024 * 1024);
|
||||
const roundedMemory = totalMemory.toFixed(2);
|
||||
|
||||
latestCommitHash = stdout.trim();
|
||||
});
|
||||
execSync('git rev-list HEAD -n 1 --abbrev-commit', (error, stdout, stderr) => {
|
||||
if (error || stderr) {
|
||||
console.error(`Error executing command: ${error || stderr}`);
|
||||
return;
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
|
@ -58,21 +58,21 @@ const ChannelTabs = {
|
||||
|
||||
module.exports = function (app, config, renderTemplate) {
|
||||
app.get("/download", async (req, res) => {
|
||||
try {
|
||||
const v = req.query.v;
|
||||
try {
|
||||
const v = req.query.v;
|
||||
|
||||
const thumbnailUrl = `https://i.ytimg.com/vi/${v}/maxresdefault.jpg`;
|
||||
const colors = await modules.getColors(thumbnailUrl);
|
||||
const color = colors[0].hex();
|
||||
const thumbnailUrl = `https://i.ytimg.com/vi/${v}/maxresdefault.jpg`;
|
||||
const colors = await modules.getColors(thumbnailUrl);
|
||||
const color = colors[0].hex();
|
||||
|
||||
renderTemplate(res, req, "download.ejs", {
|
||||
v,
|
||||
color,
|
||||
isMobile: req.useragent.isMobile,
|
||||
});
|
||||
} catch (error) {
|
||||
res.redirect("/");
|
||||
}
|
||||
renderTemplate(res, req, "download.ejs", {
|
||||
v,
|
||||
color,
|
||||
isMobile: req.useragent.isMobile,
|
||||
});
|
||||
} catch (error) {
|
||||
res.redirect("/");
|
||||
}
|
||||
});
|
||||
|
||||
app.get("/old/watch", async function (req, res) {
|
||||
@ -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,17 +152,20 @@ module.exports = function (app, config, renderTemplate) {
|
||||
try {
|
||||
const headers = {};
|
||||
|
||||
let searchUrl;
|
||||
if (req.query.from === 'hashtag') {
|
||||
searchUrl = `${config.invapi}/hashtag/${query}?hl=en-gb`;
|
||||
} 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)
|
||||
.then((res) => res.text())
|
||||
.then((txt) => getJson(txt));
|
||||
let searchUrl;
|
||||
if (req.query.from === 'hashtag') {
|
||||
searchUrl = `${config.invapi}/hashtag/${query}?hl=en-gb`;
|
||||
} 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, {
|
||||
headers: {
|
||||
'User-Agent': config.useragent,
|
||||
},
|
||||
})
|
||||
.then((res) => res.text())
|
||||
.then((txt) => getJson(txt));
|
||||
|
||||
renderTemplate(res, req, "search.ejs", {
|
||||
invresults: xmlData,
|
||||
@ -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) {
|
||||
@ -247,25 +257,25 @@ const xmlData = await fetch(searchUrl)
|
||||
};
|
||||
|
||||
const apiUrl = config.invapi + "/channels/";
|
||||
const channelUrl = `${apiUrl}${ID}/${atob(
|
||||
ChannelTabs.videos
|
||||
)}?sort_by=${sort_by}${continuation}`;
|
||||
const channelUrl = `${apiUrl}${ID}/${atob(
|
||||
ChannelTabs.videos
|
||||
)}?sort_by=${sort_by}${continuation}`;
|
||||
|
||||
const shortsUrl = `${apiUrl}${ID}/${atob(
|
||||
ChannelTabs.shorts
|
||||
)}?sort_by=${sort_by}${continuation}`;
|
||||
const shortsUrl = `${apiUrl}${ID}/${atob(
|
||||
ChannelTabs.shorts
|
||||
)}?sort_by=${sort_by}${continuation}`;
|
||||
|
||||
const streamUrl = `${apiUrl}${ID}/${atob(
|
||||
ChannelTabs.streams
|
||||
)}?sort_by=${sort_by}${continuation}`;
|
||||
const streamUrl = `${apiUrl}${ID}/${atob(
|
||||
ChannelTabs.streams
|
||||
)}?sort_by=${sort_by}${continuation}`;
|
||||
|
||||
const communityUrl = `${apiUrl}${ID}/${atob(
|
||||
ChannelTabs.community
|
||||
)}?hl=en-US`;
|
||||
const communityUrl = `${apiUrl}${ID}/${atob(
|
||||
ChannelTabs.community
|
||||
)}?hl=en-US`;
|
||||
|
||||
const PlaylistUrl = `${apiUrl}${ID}/${atob(
|
||||
ChannelTabs.playlist
|
||||
)}?hl=en-US`;
|
||||
const PlaylistUrl = `${apiUrl}${ID}/${atob(
|
||||
ChannelTabs.playlist
|
||||
)}?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 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) {
|
||||
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.`
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
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.`
|
||||
};
|
||||
}
|
||||
|
||||
function getThumbnailUrl(video) {
|
||||
const maxresDefaultThumbnail = video.videoThumbnails.find(
|
||||
@ -333,12 +339,10 @@ if (bannedchannels.some(channel => channel === ID) && !bypassExists && !tabExist
|
||||
);
|
||||
const dnoreplace = about?.Description.toString();
|
||||
|
||||
|
||||
|
||||
let ChannelFirstVideoObject = {
|
||||
subCountText: "0",
|
||||
authorVerified: false,
|
||||
};
|
||||
subCountText: "0",
|
||||
authorVerified: false,
|
||||
};
|
||||
|
||||
renderTemplate(res, req, "channel.ejs", {
|
||||
ID,
|
||||
@ -363,10 +367,9 @@ if (bannedchannels.some(channel => channel === ID) && !bypassExists && !tabExist
|
||||
isMobile: req.useragent.isMobile,
|
||||
about,
|
||||
playlist,
|
||||
subs:
|
||||
typeof subscribers === "string"
|
||||
? subscribers.replace("subscribers", "")
|
||||
: "None",
|
||||
subs: typeof subscribers === "string"
|
||||
? subscribers.replace("subscribers", "")
|
||||
: "None",
|
||||
desc: dnoreplace === "[object Object]" ? "" : description,
|
||||
});
|
||||
} catch (error) {
|
||||
|
@ -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");
|
||||
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 headers = { "User-Agent": config.useragent };
|
||||
|
||||
const p = getJson(await playlist.text());
|
||||
var mediaproxy = config.media_proxy;
|
||||
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`, { headers });
|
||||
const p = getJson(await playlist.text());
|
||||
var mediaproxy = config.media_proxy;
|
||||
if (req.useragent.source.includes("Pardus")) {
|
||||
mediaproxy = "https://media-proxy.ashley0143.xyz";
|
||||
}
|
||||
renderTemplate(res, req, "playlist.ejs", { p, mediaproxy });
|
||||
});
|
||||
|
||||
if (req.useragent.source.includes("Pardus")) {
|
||||
var mediaproxy = "https://media-proxy.ashley0143.xyz";
|
||||
}
|
||||
|
||||
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)) {
|
||||
|
@ -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")) {
|
||||
|
@ -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}®ion=${contentregion}&h=${btoa(Date.now())}`).then((res) => res.text()),
|
||||
fetchWithRetry(`${this.config.invapi}/videos/${v}?hl=${contentlang}®ion=${contentregion}&h=${btoa(Date.now())}`).then((res) => res.text()),
|
||||
curly
|
||||
.get(`${this.config.tubeApi}video?v=${v}`, {
|
||||
const [invComments, videoInfo, videoData] = await Promise.all([
|
||||
fetchWithRetry(`${this.config.invapi}/comments/${v}?hl=${contentlang}®ion=${contentregion}&h=${btoa(Date.now())}`).then(res => res.text()),
|
||||
fetchWithRetry(`${this.config.invapi}/videos/${v}?hl=${contentlang}®ion=${contentregion}&h=${btoa(Date.now())}`).then(res => res.text()),
|
||||
curly.get(`${this.config.tubeApi}video?v=${v}`, {
|
||||
httpHeader: Object.entries(headers).map(([k, v]) => `${k}: ${v}`),
|
||||
})
|
||||
.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 { json, video } = videoData;
|
||||
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}®ion=${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}®ion=${contentregion}`);
|
||||
p = this.getJson(await uploads.text());
|
||||
}
|
||||
|
||||
if (!vid) {
|
||||
console.log(
|
||||
`Sorry nya, we couldn't find any information about that video qwq`
|
||||
);
|
||||
}
|
||||
if (!vid) {
|
||||
console.log(`Sorry nya, we couldn't find any information about that video qwq`);
|
||||
}
|
||||
|
||||
if (this.checkUnexistingObject(vid)) {
|
||||
const fe = await getdislikes(v);
|
||||
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 false;
|
||||
} catch (error) {
|
||||
this.initError("Error getting video", error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize an error.
|
||||
* @param {string} args - Error message.
|
||||
* @param {Error} error - Error object.
|
||||
*/
|
||||
isvalidvideo(v) {
|
||||
if (v != "assets" && v != "cdn-cgi" && v != "404") {
|
||||
return /^([a-zA-Z0-9_-]{11})/.test(v);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user