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
|
package-lock.json
|
||||||
.env
|
.env
|
||||||
json.sqlite
|
json.sqlite
|
||||||
|
config.json
|
@ -4,6 +4,7 @@
|
|||||||
"dislikes": "https://returnyoutubedislikeapi.com/votes?videoId=",
|
"dislikes": "https://returnyoutubedislikeapi.com/votes?videoId=",
|
||||||
"invchannel": "https://invid-api.poketube.fun/api/v1",
|
"invchannel": "https://invid-api.poketube.fun/api/v1",
|
||||||
"p_url":"https://p.poketube.fun",
|
"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",
|
"media_proxy": "https://image-proxy.poketube.fun",
|
||||||
"videourl":"https://eu-proxy.poketube.fun",
|
"videourl":"https://eu-proxy.poketube.fun",
|
||||||
"email_main_url":"https://email-server.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"
|
(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)})()};);
|
||||||
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;
|
|
||||||
}
|
|
||||||
});
|
|
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:
|
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
|
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
|
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 href=/css/yt-ukraine.svg?v=7 rel=icon>
|
||||||
<link rel="manifest" href="/manifest.json">
|
<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 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") { %>
|
<% 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">
|
property="twitter:description">
|
||||||
<meta content="https://cdn.glitch.global/302c6ee0-629f-453b-9024-bad1f8d7be36/9fhFiXJ.png?v=1717357642758"
|
<meta content="https://cdn.glitch.global/302c6ee0-629f-453b-9024-bad1f8d7be36/9fhFiXJ.png?v=1717357642758"
|
||||||
property="og:image">
|
property="og:image">
|
||||||
<% } else { %>
|
<% } 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">
|
property="twitter:description">
|
||||||
<meta content="https://cdn.glitch.global/302c6ee0-629f-453b-9024-bad1f8d7be36/poke.png?v=1716216428745"
|
<meta content="https://cdn.glitch.global/302c6ee0-629f-453b-9024-bad1f8d7be36/poke.png?v=1716216428745"
|
||||||
property="og:image">
|
property="og:image">
|
||||||
@ -117,8 +117,8 @@
|
|||||||
<%- include('./partials/header.ejs') %>
|
<%- include('./partials/header.ejs') %>
|
||||||
<video playsinline muted paused><source src="/bg-480.webm" type="video/webm"/></video>
|
<video playsinline muted paused><source src="/bg-480.webm" type="video/webm"/></video>
|
||||||
<div class="landing">
|
<div class="landing">
|
||||||
<h1 style="text-align: center;">GUESS WHO'S BACK ...</h1>
|
<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;">...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>
|
<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;">
|
<div style="text-align: center; padding: 10px; border-radius: 8px;margin-left: -1em;">
|
||||||
<details>
|
<details>
|
||||||
<summary style="cursor: pointer; color: white; font-size: 18px; text-decoration: underline;">
|
<summary style="cursor: pointer; color: white; font-size: 18px; text-decoration: underline;">
|
||||||
@ -152,11 +152,14 @@
|
|||||||
<img src="/static/Poke-Mobile.jpg" />
|
<img src="/static/Poke-Mobile.jpg" />
|
||||||
</div>
|
</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>
|
<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 = [
|
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: "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: "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: "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>" }
|
{ 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_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_text='Discord',
|
||||||
secondary_link='https://discord.poketube.fun',
|
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',
|
<%- include('./partials/card',
|
||||||
|
@ -1,109 +1,146 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<title>Poke - <%=error%> !!!</title>
|
<title>Poke - <%= error %> !!!</title>
|
||||||
<meta content="#111111" name="theme-color" />
|
<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="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no, viewport-fit=cover" />
|
||||||
<meta name="darkreader-lock" />
|
<meta name="darkreader-lock" />
|
||||||
<% if (description == "This helps protect our community. Learn more (TRYING AGAIN....)") { %>
|
<link href="/css/yt-ukraine.svg?v=3" rel="icon" />
|
||||||
<meta http-equiv="refresh" content="5">
|
<link rel="manifest" href="/manifest.json" />
|
||||||
<% } %>
|
<style>
|
||||||
<link href="/css/yt-ukraine.svg?v=3" rel="icon" />
|
body {
|
||||||
<link rel="manifest" href="/manifest.json" />
|
margin: auto;
|
||||||
<style>
|
background: #111111;
|
||||||
body {
|
color: white;
|
||||||
margin: auto;
|
font-family: arial;
|
||||||
background: #111111;
|
max-width: 600px;
|
||||||
color: white;
|
}
|
||||||
font-family: arial;
|
body::before {
|
||||||
max-width: 600px;
|
background: linear-gradient(0deg, rgba(115, 32, 67, 1), rgba(17, 17, 17, 1));
|
||||||
}
|
background-repeat: no-repeat;
|
||||||
body::before {
|
content: "";
|
||||||
background: linear-gradient(0deg, rgba(115, 32, 67, 1), rgba(17, 17, 17, 1));
|
position: fixed;
|
||||||
background-repeat: no-repeat;
|
bottom: 0px;
|
||||||
content: "";
|
left: 0px;
|
||||||
position: fixed;
|
width: 100%;
|
||||||
bottom: 0px;
|
height: 100%;
|
||||||
left: 0px;
|
z-index: -1;
|
||||||
width: 100%;
|
pointer-events: none;
|
||||||
height: 100%;
|
transition: 1s height;
|
||||||
z-index: -1;
|
}
|
||||||
pointer-events: none;
|
|
||||||
transition: 1s height;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
font-size: 42px;
|
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 {
|
p#abstract {
|
||||||
position: fixed;
|
transform: translate(-50%, -50%) rotate(90deg) !important;
|
||||||
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) {
|
.error {
|
||||||
p#abstract {
|
position: fixed;
|
||||||
transform: translate(-50%, -50%) rotate(90deg) !important;
|
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...";
|
||||||
}
|
}
|
||||||
|
if (seconds <= 0) {
|
||||||
.error {
|
location.reload();
|
||||||
position: fixed;
|
} else {
|
||||||
top: 50%;
|
seconds--;
|
||||||
left: 50%;
|
setTimeout(updateCountdown, 1000);
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
text-align: center;
|
|
||||||
cursor: default;
|
|
||||||
max-width: 600px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
.error-footer {
|
window.addEventListener('DOMContentLoaded', updateCountdown);
|
||||||
position: fixed;
|
</script>
|
||||||
bottom: 24px;
|
<% } else { %>
|
||||||
width: 100%;
|
<script>
|
||||||
max-width: 600px;
|
// Clear reload count on non-restart errors
|
||||||
text-align: center;
|
localStorage.removeItem('reloadCount');
|
||||||
}
|
</script>
|
||||||
.error-footer a {
|
<% } %>
|
||||||
color: #ac8fa5;
|
</head>
|
||||||
text-decoration: none;
|
<body>
|
||||||
margin: 0px 12px;
|
<% if (description === RESTART_MSG) { %>
|
||||||
}
|
|
||||||
.error-footer a:hover {
|
|
||||||
color: #d69cc8;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<% if (description == "This helps protect our community. Learn more (TRYING AGAIN....)") { %>
|
|
||||||
|
|
||||||
<p id="abstract">502</p>
|
<p id="abstract">502</p>
|
||||||
<% } else if (description !== "This helps protect our community. Learn more (TRYING AGAIN....)") { %>
|
<% } else { %>
|
||||||
<p id="abstract">404</p>
|
<p id="abstract">404</p>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
<% } %>
|
<div class="error">
|
||||||
|
<h2><%= error %></h2>
|
||||||
<div class="error">
|
<p><%= description %></p>
|
||||||
<h2><%=error%></h2>
|
<% if (description === RESTART_MSG) { %>
|
||||||
<p><%=description%></p>
|
<div class="countdown" id="countdown"></div>
|
||||||
</div>
|
<% } %>
|
||||||
<div class="error-footer">
|
</div>
|
||||||
<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-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="https://github.com/iv-org/invidious/issues">See Invidious issues</a>
|
||||||
<a href="">Refresh Page</a>
|
<a href="">Refresh Page</a>
|
||||||
<% } %>
|
<% } %>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
176
html/map.ejs
176
html/map.ejs
@ -22,7 +22,7 @@
|
|||||||
* @licstart The following is the entire license notice for the JavaScript
|
* @licstart The following is the entire license notice for the JavaScript
|
||||||
* code in this page.
|
* 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
|
* 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
|
* it and/or modify it under the terms of the GNU General Public License
|
||||||
@ -44,6 +44,178 @@
|
|||||||
|
|
||||||
//--><!]]>
|
//--><!]]>
|
||||||
</script>
|
</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>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -11,8 +11,7 @@
|
|||||||
<% if (has_secondary_action=="true") { %>
|
<% if (has_secondary_action=="true") { %>
|
||||||
<a class="card-secondary" href="<%= secondary_link %>"><%- secondary_icon %> <%= secondary_text %></a>
|
<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>
|
</div>
|
||||||
|
|
||||||
|
588
html/search.ejs
588
html/search.ejs
@ -424,7 +424,10 @@ video[counter].classList.add("shake");
|
|||||||
</div> </div>
|
</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()">
|
<button title="Play/Pause Ambient music" class="a" id="audioButton" onclick="toggleAudio()">
|
||||||
<i id="audioIcon" class="fas fa-pause"></i>
|
<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">
|
<div id="filters-box"><form action="/search" method="get">
|
||||||
<input type="hidden" name="query" value="<%- q %>">
|
<input type="hidden" name="query" value="<%- q %>">
|
||||||
<input type="hidden" name="continuation" value="<%- continuation %>">
|
<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>
|
<legend><div class="filter-name underlined">Upload date</div></legend>
|
||||||
<div class="filter-options">
|
<div class="filter-options">
|
||||||
<% const selectedDate = date || "none"; %>
|
<% const selectedDate = date || "none"; %>
|
||||||
@ -494,7 +497,8 @@ video[counter].classList.add("shake");
|
|||||||
<% }) %>
|
<% }) %>
|
||||||
|
|
||||||
</div> </fieldset></div>
|
</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>
|
</div>
|
||||||
</form></div> </details></div>
|
</form></div> </details></div>
|
||||||
@ -511,23 +515,22 @@ Web </a>
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<%
|
<%
|
||||||
|
|
||||||
|
const query = q.toLowerCase().trim();
|
||||||
|
let answer = '';
|
||||||
|
|
||||||
function isMathExpression(query) {
|
function isMathExpression(query) {
|
||||||
return /^[0-9\s\+\-\*\/\.\x]+$/.test(query);
|
return /^[0-9\s\+\-\*\/\.\x]+$/.test(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
function evaluateMathExpression(expression) {
|
if (/^[0-9\s+\-*/.x]+$/.test(query)) {
|
||||||
// twenyone
|
const expr = query.replace(/\s+/g, '');
|
||||||
if (expression.replace(/\s+/g, '') === '9+10') {
|
answer = expr === '9+10' ? '21' : (() => {
|
||||||
return '21';
|
try { return eval(expr); } catch { return 'Invalid Expression'; }
|
||||||
|
})();
|
||||||
|
return answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
return eval(expression);
|
|
||||||
} catch (error) {
|
|
||||||
return 'Invalid Expression';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getCurrentDate() {
|
function getCurrentDate() {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
return now.toLocaleDateString();
|
return now.toLocaleDateString();
|
||||||
@ -538,58 +541,138 @@ function getCurrentYear() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getTimeInTimezone(location) {
|
function getTimeInTimezone(location) {
|
||||||
const timezones = {
|
const tzMap = {
|
||||||
"california": "America/Los_Angeles",
|
"california": "America/Los_Angeles",
|
||||||
"new york": "America/New_York",
|
"new york": "America/New_York",
|
||||||
"chicago": "America/Chicago",
|
"chicago": "America/Chicago",
|
||||||
"denver": "America/Denver",
|
"denver": "America/Denver",
|
||||||
"phoenix": "America/Phoenix",
|
"phoenix": "America/Phoenix",
|
||||||
"anchorage": "America/Anchorage",
|
"anchorage": "America/Anchorage",
|
||||||
"honolulu": "Pacific/Honolulu",
|
"honolulu": "Pacific/Honolulu",
|
||||||
"london": "Europe/London",
|
"london": "Europe/London",
|
||||||
"paris": "Europe/Paris",
|
"paris": "Europe/Paris",
|
||||||
"berlin": "Europe/Berlin",
|
"berlin": "Europe/Berlin",
|
||||||
"madrid": "Europe/Madrid",
|
"madrid": "Europe/Madrid",
|
||||||
"rome": "Europe/Rome",
|
"rome": "Europe/Rome",
|
||||||
"moscow": "Europe/Moscow",
|
"moscow": "Europe/Moscow",
|
||||||
"athens": "Europe/Athens",
|
"athens": "Europe/Athens",
|
||||||
"sydney": "Australia/Sydney",
|
"sydney": "Australia/Sydney",
|
||||||
"melbourne": "Australia/Melbourne",
|
"melbourne": "Australia/Melbourne",
|
||||||
"brisbane": "Australia/Brisbane",
|
"brisbane": "Australia/Brisbane",
|
||||||
"perth": "Australia/Perth",
|
"perth": "Australia/Perth",
|
||||||
"tokyo": "Asia/Tokyo",
|
"tokyo": "Asia/Tokyo",
|
||||||
"osaka": "Asia/Osaka",
|
"osaka": "Asia/Osaka",
|
||||||
"seoul": "Asia/Seoul",
|
"seoul": "Asia/Seoul",
|
||||||
"beijing": "Asia/Shanghai",
|
"beijing": "Asia/Shanghai",
|
||||||
"shanghai": "Asia/Shanghai",
|
"shanghai": "Asia/Shanghai",
|
||||||
"hong kong": "Asia/Hong_Kong",
|
"hong kong": "Asia/Hong_Kong",
|
||||||
"taipei": "Asia/Taipei",
|
"taipei": "Asia/Taipei",
|
||||||
"bangkok": "Asia/Bangkok",
|
"bangkok": "Asia/Bangkok",
|
||||||
"jakarta": "Asia/Jakarta",
|
"jakarta": "Asia/Jakarta",
|
||||||
"delhi": "Asia/Kolkata",
|
"delhi": "Asia/Kolkata",
|
||||||
"mumbai": "Asia/Kolkata",
|
"mumbai": "Asia/Kolkata",
|
||||||
"kolkata": "Asia/Kolkata",
|
"karachi": "Asia/Karachi",
|
||||||
"karachi": "Asia/Karachi",
|
"dubai": "Asia/Dubai",
|
||||||
"lahore": "Asia/Karachi",
|
"abu dhabi": "Asia/Dubai",
|
||||||
"dubai": "Asia/Dubai",
|
"riyadh": "Asia/Riyadh",
|
||||||
"abu dhabi": "Asia/Dubai",
|
"johannesburg": "Africa/Johannesburg",
|
||||||
"riyadh": "Asia/Riyadh",
|
"cairo": "Africa/Cairo",
|
||||||
"johannesburg": "Africa/Johannesburg",
|
"nairobi": "Africa/Nairobi",
|
||||||
"cairo": "Africa/Cairo",
|
"lagos": "Africa/Lagos",
|
||||||
"nairobi": "Africa/Nairobi",
|
"algiers": "Africa/Algiers",
|
||||||
"lagos": "Africa/Lagos",
|
"casablanca": "Africa/Casablanca",
|
||||||
"algiers": "Africa/Algiers",
|
"lisbon": "Europe/Lisbon",
|
||||||
"casablanca": "Africa/Casablanca",
|
"dublin": "Europe/Dublin",
|
||||||
"lisbon": "Europe/Lisbon",
|
"zurich": "Europe/Zurich",
|
||||||
"dublin": "Europe/Dublin",
|
"vienna": "Europe/Vienna",
|
||||||
"zurich": "Europe/Zurich",
|
"stockholm": "Europe/Stockholm",
|
||||||
"vienna": "Europe/Vienna",
|
"oslo": "Europe/Oslo",
|
||||||
"stockholm": "Europe/Stockholm",
|
"helsinki": "Europe/Helsinki",
|
||||||
"oslo": "Europe/Oslo",
|
"prague": "Europe/Prague",
|
||||||
"helsinki": "Europe/Helsinki"
|
"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) {
|
if (!timezone) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -599,9 +682,186 @@ function getTimeInTimezone(location) {
|
|||||||
return now.toLocaleTimeString('en-US', options);
|
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)) {
|
if (isMathExpression(query)) {
|
||||||
answer = evaluateMathExpression(query);
|
answer = evaluateMathExpression(query);
|
||||||
} else if (query.includes('date') || query.includes('what date is it')) {
|
} else if (query.includes('date') || query.includes('what date is it')) {
|
||||||
@ -618,16 +878,69 @@ if (isMathExpression(query)) {
|
|||||||
const options = { weekday: 'long' };
|
const options = { weekday: 'long' };
|
||||||
answer = now.toLocaleDateString(undefined, options);
|
answer = now.toLocaleDateString(undefined, options);
|
||||||
} else if (query.includes('u are cute') || query.includes('you are cute')) {
|
} 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')) {
|
} 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?')) {
|
} 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?')) {
|
} 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')) {
|
} 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 = [
|
const upsellMessages = [
|
||||||
"[new] Try searching 'What's 4+4?'",
|
"[new] Try searching 'What's 4+4?'",
|
||||||
@ -653,31 +966,110 @@ function extractQueryFromUpsellMessage(message) {
|
|||||||
%>
|
%>
|
||||||
%>
|
%>
|
||||||
<% if (answer) { %>
|
<% if (answer) { %>
|
||||||
<div class="container">
|
<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;">
|
<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
|
Answer to ur question
|
||||||
</h2>
|
</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>
|
<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;">
|
||||||
<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>
|
<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>
|
</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) { %>
|
<% } 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 -->
|
<!-- 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) { %>
|
<a href="/channel?id=<%= x.authorId %>"><%= x.author %><% if (x?.authorVerified) { %>
|
||||||
<i class="icon ion ion-md-checkmark-circle" title="verified channel"></i><% } %></a>
|
<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;">
|
<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;">
|
<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>
|
<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>
|
</div>
|
||||||
</a>
|
</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;">
|
<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>
|
<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>
|
</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>
|
<i class="icon ion ion-md-checkmark-circle" title="verified channel"></i><% } %></a>
|
||||||
</div>
|
</div>
|
||||||
<div style="display: inline-flex;flex-direction: row;min-width: 6em;gap: 4px;">
|
<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;">
|
<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>
|
<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>
|
</div>
|
||||||
</a>
|
</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;">
|
<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>
|
<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>
|
</div>
|
||||||
|
@ -16,174 +16,8 @@
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see https://www.gnu.org/licenses/.
|
along with this program. If not, see https://www.gnu.org/licenses/.
|
||||||
-->
|
-->
|
||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
<% const languageOptions = [
|
||||||
<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 = [
|
|
||||||
{ code: 'autodetect', name: 'Autodetect' },
|
{ code: 'autodetect', name: 'Autodetect' },
|
||||||
{ code: 'af', name: 'Afrikaans' },
|
{ code: 'af', name: 'Afrikaans' },
|
||||||
{ code: 'sq', name: 'Albanian' },
|
{ code: 'sq', name: 'Albanian' },
|
||||||
@ -278,71 +112,285 @@
|
|||||||
{ code: 'yi', name: 'Yiddish' },
|
{ code: 'yi', name: 'Yiddish' },
|
||||||
{ code: 'yo', name: 'Yoruba' },
|
{ code: 'yo', name: 'Yoruba' },
|
||||||
{ code: 'zu', name: 'Zulu' }
|
{ 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)) {
|
if (!isValidYouTubeID(v) || isLetterSpam(v)) {
|
||||||
reason = "Video not found >~<";
|
reason = "Video not found >~<";
|
||||||
} else {
|
} 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>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</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>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
@ -1024,7 +1025,7 @@ Offical Discord Server! :3
|
|||||||
|
|
||||||
<% if (itag && !qua) { %>
|
<% if (itag && !qua) { %>
|
||||||
<audio id="aud" preload>
|
<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>
|
</audio>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
<audio id="aud"></audio>
|
<audio id="aud"></audio>
|
||||||
@ -1038,7 +1039,7 @@ Offical Discord Server! :3
|
|||||||
<% } %>
|
<% } %>
|
||||||
</noscript>
|
</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 (isvidious) { %>
|
||||||
<% if (!qua) { %>
|
<% 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") { %>
|
<% 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>
|
</p>
|
||||||
|
|
||||||
</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><% } %></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>
|
<center>
|
||||||
<a href="#top">Go To Top</a>
|
<a href="#top">Go To Top</a>
|
||||||
</center>
|
</center>
|
||||||
@ -1837,13 +1838,7 @@ WIP! </a>
|
|||||||
<input title="autoplay the next video" name="continue" id="continue" type="checkbox" >
|
<input title="autoplay the next video" name="continue" id="continue" type="checkbox" >
|
||||||
</div>
|
</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) { %>
|
<% if (!f) { %>
|
||||||
|
|
||||||
<div class="tags rec" style="margin-left:auto">
|
<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';
|
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;">
|
<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") %>
|
<%-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",
|
"activitypub-express": "^4.4.1",
|
||||||
"duck-duck-scrape": "^2.2.5",
|
"duck-duck-scrape": "^2.2.5",
|
||||||
"google-it": "^1.6.4",
|
"google-it": "^1.6.4",
|
||||||
"youtubei.js": "^9.3.0"
|
"youtubei.js": "^13.4.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
|
@ -23,118 +23,114 @@ var ping = require("ping");
|
|||||||
|
|
||||||
const sha384 = modules.hash;
|
const sha384 = modules.hash;
|
||||||
|
|
||||||
|
|
||||||
const splash = [
|
const splash = [
|
||||||
"Woke!",
|
"Woke!",
|
||||||
"Gay gay homosexaul gay!",
|
"Gay gay homosexaul gay!",
|
||||||
"free Palestine!",
|
"free Palestine!",
|
||||||
"free software!",
|
"free software!",
|
||||||
"im... stuff!",
|
"im... stuff!",
|
||||||
"frick capitalism!",
|
"frick capitalism!",
|
||||||
"still calling it twitter btw!",
|
"still calling it twitter btw!",
|
||||||
"boop!",
|
"boop!",
|
||||||
"no way!",
|
"no way!",
|
||||||
"traaaa rightssss!",
|
"traaaa rightssss!",
|
||||||
"XD!",
|
"XD!",
|
||||||
"nya!",
|
"nya!",
|
||||||
"say gex!",
|
"say gex!",
|
||||||
"ur valid :3",
|
"ur valid :3",
|
||||||
"gay space communism!",
|
"gay space communism!",
|
||||||
"doesnt have AI!",
|
"doesnt have AI!",
|
||||||
"no web3!",
|
"no web3!",
|
||||||
"keemstar is a bald ___!",
|
"keemstar is a bald ___!",
|
||||||
"No One calls it 'X'! ",
|
"No One calls it 'X'! ",
|
||||||
"Eat the rich!",
|
"Eat the rich!",
|
||||||
"Does Not include Nazis!",
|
"Does Not include Nazis!",
|
||||||
"also try piped!",
|
"also try piped!",
|
||||||
"not alt-right!",
|
"not alt-right!",
|
||||||
"coke zero > coke classic!",
|
"coke zero > coke classic!",
|
||||||
"poke & chill!",
|
"poke & chill!",
|
||||||
"can play HD!",
|
"can play HD!",
|
||||||
"also try invidious!",
|
"also try invidious!",
|
||||||
"also try vencord!",
|
"also try vencord!",
|
||||||
"rms <3!",
|
"rms <3!",
|
||||||
"du hast",
|
"du hast",
|
||||||
"can u belive no one bought this?",
|
"can u belive no one bought this?",
|
||||||
"reee",
|
"reee",
|
||||||
"1.000.000€!",
|
"1.000.000€!",
|
||||||
"pika!",
|
"pika!",
|
||||||
"fsf.org",
|
"fsf.org",
|
||||||
"ssfffssfssfffaassssfsdf!",
|
"ssfffssfssfffaassssfsdf!",
|
||||||
"𝓯𝓻𝓮𝓪𝓴𝔂poke",
|
"𝓯𝓻𝓮𝓪𝓴𝔂poke",
|
||||||
"they not like us!",
|
"they not like us!",
|
||||||
"to pimp a butterfly!",
|
"to pimp a butterfly!",
|
||||||
"king kunta!",
|
"king kunta!",
|
||||||
"HUMBLE.",
|
"HUMBLE.",
|
||||||
"can you save my hds?",
|
"can you save my hds?",
|
||||||
"sahlo folina!",
|
"sahlo folina!",
|
||||||
"we come for you!",
|
"we come for you!",
|
||||||
"no chances!",
|
"no chances!",
|
||||||
"dema dont control us!",
|
"dema dont control us!",
|
||||||
"i see your problem is, your proctologist",
|
"i see your problem is, your proctologist",
|
||||||
"got both hands on your shoulder",
|
"got both hands on your shoulder",
|
||||||
"while ur bottomless!",
|
"while ur bottomless!",
|
||||||
"you should bounce bounce bounce man!",
|
"you should bounce bounce bounce man!",
|
||||||
"its lavish!",
|
"its lavish!",
|
||||||
"im vibin, vibin!",
|
"im vibin, vibin!",
|
||||||
"i would swim the paladin strait",
|
"i would swim the paladin strait",
|
||||||
"hello clancy!",
|
"hello clancy!",
|
||||||
"NO NOT ME,ITS FOR A FRIEND",
|
"NO NOT ME,ITS FOR A FRIEND",
|
||||||
"im fairly local!",
|
"im fairly local!",
|
||||||
"i dont wanna go like this!",
|
"i dont wanna go like this!",
|
||||||
"east is up!",
|
"east is up!",
|
||||||
"not done, josh dun!",
|
"not done, josh dun!",
|
||||||
"your the judge, oh no!",
|
"your the judge, oh no!",
|
||||||
"I dont wanna backslide",
|
"I dont wanna backslide",
|
||||||
"welcome back to trench!",
|
"welcome back to trench!",
|
||||||
"sai is propaganda!",
|
"sai is propaganda!",
|
||||||
" •|i|• Ø i+! ].[",
|
" •|i|• Ø i+! ].[",
|
||||||
"stay alive! |-/",
|
"stay alive! |-/",
|
||||||
"the few, the proud, the Emotional!",
|
"the few, the proud, the Emotional!",
|
||||||
"ill morph into someone else",
|
"ill morph into someone else",
|
||||||
"still alive",
|
"still alive",
|
||||||
"follow the torches",
|
"follow the torches",
|
||||||
"i created this world!",
|
"i created this world!",
|
||||||
"to feel some control!",
|
"to feel some control!",
|
||||||
"destory it if i want!",
|
"destory it if i want!",
|
||||||
"o7 keons",
|
"o7 keons",
|
||||||
"at least let me clean my room",
|
"at least let me clean my room",
|
||||||
"100+ stars on gh!",
|
"100+ stars on gh!",
|
||||||
"let the vibe slide over me!",
|
"let the vibe slide over me!",
|
||||||
"sip a capri sun like its don peregon",
|
"sip a capri sun like its don peregon",
|
||||||
"now even gayer!",
|
"now even gayer!",
|
||||||
"its joever..",
|
"its joever..",
|
||||||
"lesbiam,,,",
|
"lesbiam,,,",
|
||||||
"poke!!!",
|
"poke!!!",
|
||||||
"discord.poketube.fun!",
|
"discord.poketube.fun!",
|
||||||
"women are pretty!",
|
"women are pretty!",
|
||||||
"men are handsome!",
|
"men are handsome!",
|
||||||
"enbys are cute!",
|
"enbys are cute!",
|
||||||
"you are cute :3",
|
"you are cute :3",
|
||||||
"read if cute!",
|
"read if cute!",
|
||||||
"this shit awesome!",
|
"this shit awesome!",
|
||||||
"ur pawsome!",
|
"ur pawsome!",
|
||||||
"meows at u",
|
"meows at u",
|
||||||
"hai i am gay",
|
"hai i am gay",
|
||||||
"yay, GEX!",
|
"yay, GEX!",
|
||||||
"say gex..,,",
|
"say gex..,,",
|
||||||
"wha if we um erm",
|
"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!",
|
||||||
"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 screen!",
|
||||||
"awesome camera!",
|
"awesome camera!",
|
||||||
"long lasting battery life",
|
"long lasting battery life",
|
||||||
"stallmansupport.org!!!",
|
"stallmansupport.org!!!",
|
||||||
"does include nya~!!!",
|
"does include nya~!!!",
|
||||||
"actually stable! :3",
|
"actually stable! :3",
|
||||||
]
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function getJson(str) {
|
function getJson(str) {
|
||||||
try {
|
try {
|
||||||
@ -146,20 +142,23 @@ function getJson(str) {
|
|||||||
|
|
||||||
module.exports = function (app, config, renderTemplate) {
|
module.exports = function (app, config, renderTemplate) {
|
||||||
app.get("/app", async function (req, res) {
|
app.get("/app", async function (req, res) {
|
||||||
const { fetch } = await import("undici");
|
const { fetch } = await import("undici");
|
||||||
|
|
||||||
let tab = "";
|
let tab = "";
|
||||||
if (req.query.tab) {
|
if (req.query.tab) {
|
||||||
tab = `/?type=${capitalizeFirstLetter(req.query.tab)}`;
|
tab = `/?type=${capitalizeFirstLetter(req.query.tab)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const invtrend = await fetch(
|
const invtrend = await fetch(`${config.invapi}/trending${tab}`, {
|
||||||
`${config.invapi}/trending${tab}`
|
headers: { "User-Agent": config.useragent },
|
||||||
);
|
});
|
||||||
const t = getJson(await invtrend.text());
|
const t = getJson(await invtrend.text());
|
||||||
|
|
||||||
const invpopular = await fetch(
|
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());
|
const p = getJson(await invpopular.text());
|
||||||
|
|
||||||
@ -190,18 +189,15 @@ module.exports = function (app, config, renderTemplate) {
|
|||||||
const uaos = req.useragent.os;
|
const uaos = req.useragent.os;
|
||||||
const random = splash[Math.floor(Math.random() * splash.length)];
|
const random = splash[Math.floor(Math.random() * splash.length)];
|
||||||
const browser = req.useragent.browser;
|
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;
|
var proxyurl = config.p_url;
|
||||||
|
|
||||||
const secure = [
|
const secure = ["poketube.fun", "localhost"].includes(req.hostname);
|
||||||
"poketube.fun",
|
const verify = ["poketube.fun", "poke.ashley0143.xyz", "localhost"].includes(
|
||||||
"localhost" //
|
req.hostname
|
||||||
].includes(req.hostname);
|
);
|
||||||
const verify = [
|
|
||||||
"poketube.fun",
|
|
||||||
"poke.ashley0143.xyz",
|
|
||||||
"localhost"
|
|
||||||
].includes(req.hostname);
|
|
||||||
|
|
||||||
const rendermainpage = () => {
|
const rendermainpage = () => {
|
||||||
if (req.useragent.isMobile) {
|
if (req.useragent.isMobile) {
|
||||||
@ -210,13 +206,13 @@ module.exports = function (app, config, renderTemplate) {
|
|||||||
|
|
||||||
return renderTemplate(res, req, "landing.ejs", {
|
return renderTemplate(res, req, "landing.ejs", {
|
||||||
secure,
|
secure,
|
||||||
embedtype:req.query.embedtype,
|
embedtype: req.query.embedtype,
|
||||||
banner:config.banner,
|
banner: config.banner,
|
||||||
DisablePokeChan:req.query.DisablePokeChan,
|
DisablePokeChan: req.query.DisablePokeChan,
|
||||||
verify,
|
verify,
|
||||||
isOldWindows,
|
isOldWindows,
|
||||||
proxyurl,
|
proxyurl,
|
||||||
random
|
random,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -225,14 +221,14 @@ module.exports = function (app, config, renderTemplate) {
|
|||||||
if (isvld && req.params.v.length >= 10) {
|
if (isvld && req.params.v.length >= 10) {
|
||||||
return res.redirect(`/watch?v=${req.params.v}`);
|
return res.redirect(`/watch?v=${req.params.v}`);
|
||||||
} else {
|
} else {
|
||||||
res.status(404)
|
res.status(404);
|
||||||
return renderTemplate(res, req, "404.ejs", {
|
return renderTemplate(res, req, "404.ejs", {
|
||||||
isOldWindows,
|
isOldWindows,
|
||||||
random
|
random,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rendermainpage();
|
return rendermainpage();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -1,22 +1,5 @@
|
|||||||
const {
|
const { modules } = require("../libpoketube-initsys.js");
|
||||||
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");
|
|
||||||
|
|
||||||
var http = require("https");
|
var http = require("https");
|
||||||
var ping = require("ping");
|
var ping = require("ping");
|
||||||
|
@ -1,22 +1,4 @@
|
|||||||
const {
|
const { modules, version } = require("../libpoketube-initsys.js");
|
||||||
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");
|
|
||||||
|
|
||||||
function getJson(str) {
|
function getJson(str) {
|
||||||
try {
|
try {
|
||||||
@ -29,36 +11,43 @@ function getJson(str) {
|
|||||||
const pkg = require("../../../package.json");
|
const pkg = require("../../../package.json");
|
||||||
const os = require('os');
|
const os = require('os');
|
||||||
const cnf = require("../../../config.json");
|
const cnf = require("../../../config.json");
|
||||||
|
|
||||||
|
|
||||||
const innertube = require("../libpoketube-youtubei-objects.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 { execSync } = require('child_process'); // DO NOT ABBRV THIS :SOB:
|
||||||
const versmol = "v24.1906-sho"
|
|
||||||
|
const verfull = "v25.2705-luna-MAJOR_UPDATE-stable-dev-nonLTS-git-MTc0NTcwNjc4MA==";
|
||||||
|
const versmol = "v25.2705-luna";
|
||||||
const branch = "dev/master";
|
const branch = "dev/master";
|
||||||
const codename = "sho";
|
const codename = "luna";
|
||||||
const versionnumber = "293";
|
const versionnumber = "294";
|
||||||
const relaseunixdate = "MTcxODc5NDY3NQ=="
|
const relaseunixdate = "MTc0NTcwNjc4MA==";
|
||||||
const updatequote = "pls fund vennie plush -Bims"
|
const updatequote = "i created this world.....to feel some control...";
|
||||||
|
|
||||||
|
|
||||||
module.exports = function (app, config, renderTemplate) {
|
module.exports = function (app, config, renderTemplate) {
|
||||||
|
|
||||||
|
const headers = {
|
||||||
|
'User-Agent': config.useragent,
|
||||||
|
};
|
||||||
|
|
||||||
app.get("/vi/:v/:t", async function (req, res) {
|
app.get("/vi/:v/:t", async function (req, res) {
|
||||||
var url = `https://i.ytimg.com/vi/${req.params.v}/${req.params.t}`
|
var url = `https://i.ytimg.com/vi/${req.params.v}/${req.params.t}`;
|
||||||
|
|
||||||
let f = await modules.fetch(url + `?cachefixer=${btoa(Date.now())}`, {
|
let f = await modules.fetch(url + `?cachefixer=${btoa(Date.now())}`, {
|
||||||
method: req.method,
|
method: req.method,
|
||||||
|
headers: headers,
|
||||||
});
|
});
|
||||||
|
|
||||||
f.body.pipe(res);
|
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}`;
|
var url = `https://vid.puffyan.us/ggpht/${req.params.v}`;
|
||||||
|
|
||||||
let f = await modules.fetch(url + `?cachefixer=${btoa(Date.now())}`, {
|
let f = await modules.fetch(url + `?cachefixer=${btoa(Date.now())}`, {
|
||||||
method: req.method,
|
method: req.method,
|
||||||
|
headers: headers,
|
||||||
});
|
});
|
||||||
|
|
||||||
f.body.pipe(res);
|
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())}`, {
|
let f = await modules.fetch(url + `?cachefixer=${btoa(Date.now())}`, {
|
||||||
method: req.method,
|
method: req.method,
|
||||||
|
headers: headers,
|
||||||
});
|
});
|
||||||
|
|
||||||
f.body.pipe(res);
|
f.body.pipe(res);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
app.get("/avatars/ytc/:v", async function (req, res) {
|
app.get("/avatars/ytc/:v", async function (req, res) {
|
||||||
var url = `https://vid.puffyan.us/ggpht/ytc/${req.params.v.replace("ytc", "")}`;
|
var url = `https://vid.puffyan.us/ggpht/ytc/${req.params.v.replace("ytc", "")}`;
|
||||||
|
|
||||||
let f = await modules.fetch(url + `?cachefixer=${btoa(Date.now())}`, {
|
let f = await modules.fetch(url + `?cachefixer=${btoa(Date.now())}`, {
|
||||||
method: req.method,
|
method: req.method,
|
||||||
|
headers: headers,
|
||||||
});
|
});
|
||||||
|
|
||||||
f.body.pipe(res);
|
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) {
|
app.get("/api/video/download", async function (req, res) {
|
||||||
var v = req.query.v;
|
var v = req.query.v;
|
||||||
@ -101,170 +81,133 @@ app.get("/avatars/:v", async function (req, res) {
|
|||||||
var q = "18";
|
var q = "18";
|
||||||
if (req.query.q) q = req.query.q;
|
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);
|
res.redirect(url);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get("/api/subtitles", async (req, res) => {
|
app.get("/api/subtitles", async (req, res) => {
|
||||||
const { fetch } = await import("undici");
|
const { fetch } = await import("undici");
|
||||||
|
|
||||||
const id = req.query.v;
|
const id = req.query.v;
|
||||||
const l = req.query.h;
|
const l = req.query.h;
|
||||||
|
|
||||||
try {
|
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();
|
const body = await f.text();
|
||||||
|
|
||||||
res.send(body);
|
res.send(body);
|
||||||
} catch {}
|
} catch {}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get("/api/getEngagementData", async (req, res) => {
|
|
||||||
const { fetch } = await import("undici");
|
|
||||||
|
|
||||||
const id = req.query.v;
|
app.get("/api/getEngagementData", async (req, res) => {
|
||||||
|
|
||||||
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) => {
|
|
||||||
const { fetch } = await import("undici");
|
const { fetch } = await import("undici");
|
||||||
|
|
||||||
const id = req.query.v;
|
const id = req.query.v;
|
||||||
const l = req.query.h;
|
|
||||||
|
|
||||||
try {
|
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);
|
const response = await fetch(apiUrl, {
|
||||||
let body = await f.text();
|
headers: headers,
|
||||||
|
|
||||||
body = body.replace(/#xywh=(\d+),(\d+),(\d+),(\d+)/g, (match, x, y, w, h) => {
|
|
||||||
return `&xywh=${x},${y},${w},${h}`;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
res.send(body);
|
if (response.status === 400) {
|
||||||
} catch {}
|
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) => {
|
app.get("/feeds/videos.xml", async (req, res) => {
|
||||||
const id = req.query.channel_id;
|
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, {
|
let f = await modules.fetch(url, {
|
||||||
method: req.method,
|
method: req.method,
|
||||||
|
headers: headers, // Add headers to the fetch request
|
||||||
});
|
});
|
||||||
|
|
||||||
f.body.pipe(res);
|
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;
|
const id = req.params.id;
|
||||||
|
|
||||||
let url = `https://invid-api.poketube.fun/bHj665PpYhUdPWuKPfZuQGoX/api/manifest/dash/id/${id}`;
|
let url = `https://invid-api.poketube.fun/bHj665PpYhUdPWuKPfZuQGoX/api/manifest/dash/id/${id}`;
|
||||||
|
|
||||||
let f = await modules.fetch(url, {
|
let f = await modules.fetch(url, {
|
||||||
method: req.method,
|
method: req.method,
|
||||||
|
headers: headers,
|
||||||
});
|
});
|
||||||
|
|
||||||
f.body.pipe(res);
|
f.body.pipe(res);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
app.get("/api/redirect", async (req, res) => {
|
app.get("/api/redirect", async (req, res) => {
|
||||||
const red_url = atob(req.query.u);
|
const red_url = atob(req.query.u);
|
||||||
|
|
||||||
@ -314,38 +257,41 @@ app.use("/sb/i/:v/:imagePath/:img", async function (req, res) {
|
|||||||
let latestCommitHash;
|
let latestCommitHash;
|
||||||
|
|
||||||
const invidious = await modules
|
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((res) => res.text())
|
||||||
.then((txt) => getJson(txt));
|
.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) => {
|
const cpus = os.cpus();
|
||||||
if (error || stderr) {
|
const totalMemory = os.totalmem() / (1024 * 1024 * 1024);
|
||||||
console.error(`Error executing command: ${error || stderr}`);
|
const roundedMemory = totalMemory.toFixed(2);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 = {
|
const response = {
|
||||||
pt_version: {
|
pt_version: {
|
||||||
version:versmol,
|
version: versmol,
|
||||||
version_full:verfull,
|
version_full: verfull,
|
||||||
commit: latestCommitHash
|
commit: latestCommitHash,
|
||||||
},
|
},
|
||||||
branch,
|
branch,
|
||||||
updatequote,
|
updatequote,
|
||||||
relaseunixdate,
|
relaseunixdate,
|
||||||
vernum: versionnumber,
|
vernum: versionnumber,
|
||||||
codename,
|
codename,
|
||||||
config:cnf,
|
config: configWithoutUA,
|
||||||
system:{
|
system: {
|
||||||
ram:`${roundedMemory} GB`,
|
ram: `${roundedMemory} GB`,
|
||||||
cpu:cpus[0].model,
|
cpu: cpus[0].model,
|
||||||
},
|
},
|
||||||
packages: {
|
packages: {
|
||||||
libpt: version,
|
libpt: version,
|
||||||
@ -374,7 +320,9 @@ execSync('git rev-list HEAD -n 1 --abbrev-commit', (error, stdout, stderr) => {
|
|||||||
try {
|
try {
|
||||||
const url = `https://raw.githubusercontent.com/ashley0143/poke/main/instances.json`;
|
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((res) => res.text())
|
||||||
.then((json) => JSON.parse(json));
|
.then((json) => JSON.parse(json));
|
||||||
|
|
||||||
|
@ -58,21 +58,21 @@ const ChannelTabs = {
|
|||||||
|
|
||||||
module.exports = function (app, config, renderTemplate) {
|
module.exports = function (app, config, renderTemplate) {
|
||||||
app.get("/download", async (req, res) => {
|
app.get("/download", async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const v = req.query.v;
|
const v = req.query.v;
|
||||||
|
|
||||||
const thumbnailUrl = `https://i.ytimg.com/vi/${v}/maxresdefault.jpg`;
|
const thumbnailUrl = `https://i.ytimg.com/vi/${v}/maxresdefault.jpg`;
|
||||||
const colors = await modules.getColors(thumbnailUrl);
|
const colors = await modules.getColors(thumbnailUrl);
|
||||||
const color = colors[0].hex();
|
const color = colors[0].hex();
|
||||||
|
|
||||||
renderTemplate(res, req, "download.ejs", {
|
renderTemplate(res, req, "download.ejs", {
|
||||||
v,
|
v,
|
||||||
color,
|
color,
|
||||||
isMobile: req.useragent.isMobile,
|
isMobile: req.useragent.isMobile,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.redirect("/");
|
res.redirect("/");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get("/old/watch", async function (req, res) {
|
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);
|
res.redirect("https://lite.duckduckgo.com/lite/?q=" + query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (query && query.startsWith("Hey ChatGPT,") && query.length > 2) {
|
if (query && query.startsWith("Hey ChatGPT,") && query.length > 2) {
|
||||||
res.redirect("https://chatgpt.com/?q=" + query + "- sent using pokeAI features");
|
res.redirect("https://chatgpt.com/?q=" + query + "- sent using pokeAI features");
|
||||||
}
|
}
|
||||||
@ -153,17 +152,20 @@ module.exports = function (app, config, renderTemplate) {
|
|||||||
try {
|
try {
|
||||||
const headers = {};
|
const headers = {};
|
||||||
|
|
||||||
let searchUrl;
|
let searchUrl;
|
||||||
if (req.query.from === 'hashtag') {
|
if (req.query.from === 'hashtag') {
|
||||||
searchUrl = `${config.invapi}/hashtag/${query}?hl=en-gb`;
|
searchUrl = `${config.invapi}/hashtag/${query}?hl=en-gb`;
|
||||||
} else {
|
} else {
|
||||||
searchUrl = `${config.invapi}/search?q=${encodeURIComponent(query)}&page=${encodeURIComponent(continuation)}&date=${date}&type=${type}&duration=${duration}&sort=${sort}&hl=en+gb`;
|
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));
|
|
||||||
|
|
||||||
|
const xmlData = await fetch(searchUrl, {
|
||||||
|
headers: {
|
||||||
|
'User-Agent': config.useragent,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((res) => res.text())
|
||||||
|
.then((txt) => getJson(txt));
|
||||||
|
|
||||||
renderTemplate(res, req, "search.ejs", {
|
renderTemplate(res, req, "search.ejs", {
|
||||||
invresults: xmlData,
|
invresults: xmlData,
|
||||||
@ -218,7 +220,11 @@ const xmlData = await fetch(searchUrl)
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// about
|
// 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();
|
const h = await bout.text();
|
||||||
var boutJson = JSON.parse(modules.toJson(h));
|
var boutJson = JSON.parse(modules.toJson(h));
|
||||||
} catch {
|
} catch {
|
||||||
@ -238,7 +244,11 @@ const xmlData = await fetch(searchUrl)
|
|||||||
|
|
||||||
const getChannelData = async (url) => {
|
const getChannelData = async (url) => {
|
||||||
try {
|
try {
|
||||||
return await fetch(url)
|
return await fetch(url, {
|
||||||
|
headers: {
|
||||||
|
'User-Agent': config.useragent,
|
||||||
|
},
|
||||||
|
})
|
||||||
.then((res) => res.text())
|
.then((res) => res.text())
|
||||||
.then((txt) => getJson(txt));
|
.then((txt) => getJson(txt));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -247,25 +257,25 @@ const xmlData = await fetch(searchUrl)
|
|||||||
};
|
};
|
||||||
|
|
||||||
const apiUrl = config.invapi + "/channels/";
|
const apiUrl = config.invapi + "/channels/";
|
||||||
const channelUrl = `${apiUrl}${ID}/${atob(
|
const channelUrl = `${apiUrl}${ID}/${atob(
|
||||||
ChannelTabs.videos
|
ChannelTabs.videos
|
||||||
)}?sort_by=${sort_by}${continuation}`;
|
)}?sort_by=${sort_by}${continuation}`;
|
||||||
|
|
||||||
const shortsUrl = `${apiUrl}${ID}/${atob(
|
const shortsUrl = `${apiUrl}${ID}/${atob(
|
||||||
ChannelTabs.shorts
|
ChannelTabs.shorts
|
||||||
)}?sort_by=${sort_by}${continuation}`;
|
)}?sort_by=${sort_by}${continuation}`;
|
||||||
|
|
||||||
const streamUrl = `${apiUrl}${ID}/${atob(
|
const streamUrl = `${apiUrl}${ID}/${atob(
|
||||||
ChannelTabs.streams
|
ChannelTabs.streams
|
||||||
)}?sort_by=${sort_by}${continuation}`;
|
)}?sort_by=${sort_by}${continuation}`;
|
||||||
|
|
||||||
const communityUrl = `${apiUrl}${ID}/${atob(
|
const communityUrl = `${apiUrl}${ID}/${atob(
|
||||||
ChannelTabs.community
|
ChannelTabs.community
|
||||||
)}?hl=en-US`;
|
)}?hl=en-US`;
|
||||||
|
|
||||||
const PlaylistUrl = `${apiUrl}${ID}/${atob(
|
const PlaylistUrl = `${apiUrl}${ID}/${atob(
|
||||||
ChannelTabs.playlist
|
ChannelTabs.playlist
|
||||||
)}?hl=en-US`;
|
)}?hl=en-US`;
|
||||||
|
|
||||||
const channelINVUrl = `${apiUrl}${ID}/`;
|
const channelINVUrl = `${apiUrl}${ID}/`;
|
||||||
|
|
||||||
@ -280,22 +290,18 @@ const PlaylistUrl = `${apiUrl}${ID}/${atob(
|
|||||||
getChannelData(channelINVUrl),
|
getChannelData(channelINVUrl),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
var bannedchannels = ["UC1okSIA8UEY8OqvtjGHFvzA", "UClsVg5LkK2COQRo1mVS4taA", "UCIr4vkCsn0tdTW2xZ1jRG1g"];
|
||||||
var bannedchannels = ["UC1okSIA8UEY8OqvtjGHFvzA", "UClsVg5LkK2COQRo1mVS4taA", "UCIr4vkCsn0tdTW2xZ1jRG1g"];
|
var bypassQuery = "cG9rZXR1YmVjaGFubmVsYnlwYXNzbG9scGVvcGxldGhpbmt0aGlzaXNjZW5zb3JzaGlwLTQ1OTBh";
|
||||||
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 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) {
|
function getThumbnailUrl(video) {
|
||||||
const maxresDefaultThumbnail = video.videoThumbnails.find(
|
const maxresDefaultThumbnail = video.videoThumbnails.find(
|
||||||
@ -333,12 +339,10 @@ if (bannedchannels.some(channel => channel === ID) && !bypassExists && !tabExist
|
|||||||
);
|
);
|
||||||
const dnoreplace = about?.Description.toString();
|
const dnoreplace = about?.Description.toString();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let ChannelFirstVideoObject = {
|
let ChannelFirstVideoObject = {
|
||||||
subCountText: "0",
|
subCountText: "0",
|
||||||
authorVerified: false,
|
authorVerified: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
renderTemplate(res, req, "channel.ejs", {
|
renderTemplate(res, req, "channel.ejs", {
|
||||||
ID,
|
ID,
|
||||||
@ -363,10 +367,9 @@ if (bannedchannels.some(channel => channel === ID) && !bypassExists && !tabExist
|
|||||||
isMobile: req.useragent.isMobile,
|
isMobile: req.useragent.isMobile,
|
||||||
about,
|
about,
|
||||||
playlist,
|
playlist,
|
||||||
subs:
|
subs: typeof subscribers === "string"
|
||||||
typeof subscribers === "string"
|
? subscribers.replace("subscribers", "")
|
||||||
? subscribers.replace("subscribers", "")
|
: "None",
|
||||||
: "None",
|
|
||||||
desc: dnoreplace === "[object Object]" ? "" : description,
|
desc: dnoreplace === "[object Object]" ? "" : description,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -115,27 +115,22 @@ module.exports = function (app, config, renderTemplate) {
|
|||||||
app.get("/apps", function (req, res) {
|
app.get("/apps", function (req, res) {
|
||||||
renderTemplate(res, req, "apps.ejs");
|
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(
|
const headers = { "User-Agent": config.useragent };
|
||||||
`${config.invapi}/playlists/${req.query.list}?hl=en-us`
|
|
||||||
);
|
|
||||||
|
|
||||||
const p = getJson(await playlist.text());
|
app.get("/playlist", async function (req, res) {
|
||||||
var mediaproxy = config.media_proxy;
|
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) {
|
app.get("/license", function (req, res) {
|
||||||
renderTemplate(res, req, "license.ejs");
|
renderTemplate(res, req, "license.ejs");
|
||||||
@ -261,7 +256,7 @@ app.get('/calendar', (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
app.get("/game-hub", function (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;
|
var requestedGame = req.query.game;
|
||||||
|
|
||||||
if (req.query.game && !gameslist.includes(requestedGame)) {
|
if (req.query.game && !gameslist.includes(requestedGame)) {
|
||||||
|
@ -452,7 +452,7 @@ module.exports = function (app, config, renderTemplate) {
|
|||||||
var vidurl = u.losslessurl;
|
var vidurl = u.losslessurl;
|
||||||
}
|
}
|
||||||
|
|
||||||
var vidurl = "https://eu-proxy.poketube.fun";
|
var vidurl = config.videourl;
|
||||||
var isvidious = true;
|
var isvidious = true;
|
||||||
|
|
||||||
if (req.useragent.source.includes("Pardus")) {
|
if (req.useragent.source.includes("Pardus")) {
|
||||||
|
@ -12,20 +12,7 @@ const getdislikes = require("../libpoketube/libpoketube-dislikes.js");
|
|||||||
const getColors = require("get-image-colors");
|
const getColors = require("get-image-colors");
|
||||||
const config = require("../../config.json")
|
const config = require("../../config.json")
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class representing PokeTube's core functionality.
|
|
||||||
*/
|
|
||||||
class InnerTubePokeVidious {
|
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) {
|
constructor(config) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.cache = {};
|
this.cache = {};
|
||||||
@ -36,17 +23,12 @@ class InnerTubePokeVidious {
|
|||||||
this.ANDROID_API_KEY = "AIzaSyA8eiZmM1FaDVjRy-df2KTyQ_vz_yYM39w"
|
this.ANDROID_API_KEY = "AIzaSyA8eiZmM1FaDVjRy-df2KTyQ_vz_yYM39w"
|
||||||
this.ANDROID_APP_VERSION = "19.14.42"
|
this.ANDROID_APP_VERSION = "19.14.42"
|
||||||
this.ANDROID_VERSION = "13"
|
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.INNERTUBE_CONTEXT_CLIENT_VERSION = "1"
|
||||||
this.region = "region=US";
|
this.region = "region=US";
|
||||||
this.sqp = "-oaymwEbCKgBEF5IVfKriqkDDggBFQAAiEIYAXABwAEG&rs=AOn4CLBy_x4UUHLNDZtJtH0PXeQGoRFTgw";
|
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) {
|
getJson(str) {
|
||||||
try {
|
try {
|
||||||
return JSON.parse(str);
|
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) {
|
checkUnexistingObject(obj) {
|
||||||
if (obj) {
|
return obj && "authorId" in obj;
|
||||||
if ("authorId" in obj) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch video information.
|
|
||||||
* @param {string} v - Video ID.
|
|
||||||
* @returns {Promise<object>} Promise resolving to the video information.
|
|
||||||
*/
|
|
||||||
async getYouTubeApiVideo(f, v, contentlang, contentregion) {
|
async getYouTubeApiVideo(f, v, contentlang, contentregion) {
|
||||||
|
|
||||||
const { fetch } = await import("undici");
|
const { fetch } = await import("undici");
|
||||||
|
|
||||||
if (v == null) return "Gib ID";
|
if (v == null) return "Gib ID";
|
||||||
|
|
||||||
// Check if result is already cached
|
|
||||||
if (this.cache[v] && Date.now() - this.cache[v].timestamp < 3600000) {
|
if (this.cache[v] && Date.now() - this.cache[v].timestamp < 3600000) {
|
||||||
return this.cache[v].result;
|
return this.cache[v].result;
|
||||||
}
|
}
|
||||||
const headers = {};
|
|
||||||
|
|
||||||
let desc = "";
|
const headers = {
|
||||||
|
"User-Agent": this.useragent,
|
||||||
|
};
|
||||||
|
|
||||||
const fetchWithRetry = async (url, options = {}, retries = 3) => {
|
const fetchWithRetry = async (url, options = {}, retries = 3) => {
|
||||||
for (let attempt = 0; attempt < retries; attempt++) {
|
for (let attempt = 0; attempt < retries; attempt++) {
|
||||||
const res = await fetch(url, options);
|
const res = await fetch(url, {
|
||||||
if (res.status === 500 && attempt < retries - 1) {
|
...options,
|
||||||
continue; // retry on 500
|
headers: {
|
||||||
}
|
...options.headers,
|
||||||
|
...headers,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (res.status === 500 && attempt < retries - 1) continue;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
// If all retries fail, return last response
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const [invComments, videoInfo, videoData] = await Promise.all([
|
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}/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()),
|
fetchWithRetry(`${this.config.invapi}/videos/${v}?hl=${contentlang}®ion=${contentregion}&h=${btoa(Date.now())}`).then(res => res.text()),
|
||||||
curly
|
curly.get(`${this.config.tubeApi}video?v=${v}`, {
|
||||||
.get(`${this.config.tubeApi}video?v=${v}`, {
|
|
||||||
httpHeader: Object.entries(headers).map(([k, v]) => `${k}: ${v}`),
|
httpHeader: Object.entries(headers).map(([k, v]) => `${k}: ${v}`),
|
||||||
})
|
}).then(res => {
|
||||||
.then((res) => {
|
|
||||||
const json = toJson(res.data);
|
const json = toJson(res.data);
|
||||||
const video = this.getJson(json);
|
const video = this.getJson(json);
|
||||||
return { json, video };
|
return { json, video };
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const comments = this.getJson(invComments);
|
||||||
const comments = await this.getJson(invComments);
|
const vid = this.getJson(videoInfo);
|
||||||
|
const { json, video } = videoData;
|
||||||
const vid = await this.getJson(videoInfo);
|
|
||||||
const { json, video } = videoData;
|
|
||||||
|
|
||||||
var channel_uploads = { };
|
let p = {};
|
||||||
if (f == "true") {
|
if (f === "true") {
|
||||||
channel_uploads = await fetch(
|
const uploads = await fetchWithRetry(`${this.config.invapi}/channels/${vid.authorId}?hl=${contentlang}®ion=${contentregion}`);
|
||||||
`${this.config.invapi}/channels/${vid.authorId}?hl=${contentlang}®ion=${contentregion}`
|
p = this.getJson(await uploads.text());
|
||||||
);
|
}
|
||||||
var p = this.getJson(await channel_uploads.text());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!vid) {
|
if (!vid) {
|
||||||
console.log(
|
console.log(`Sorry nya, we couldn't find any information about that video qwq`);
|
||||||
`Sorry nya, we couldn't find any information about that video qwq`
|
}
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.checkUnexistingObject(vid)) {
|
if (this.checkUnexistingObject(vid)) {
|
||||||
const fe = await getdislikes(v);
|
const fe = await getdislikes(v);
|
||||||
|
|
||||||
try {
|
|
||||||
const headers = {};
|
|
||||||
|
|
||||||
// Store result in cache
|
|
||||||
this.cache[v] = {
|
this.cache[v] = {
|
||||||
result: {
|
result: {
|
||||||
json: json?.video,
|
json: json?.video,
|
||||||
@ -151,59 +109,38 @@ class InnerTubePokeVidious {
|
|||||||
engagement: fe.engagement,
|
engagement: fe.engagement,
|
||||||
wiki: "",
|
wiki: "",
|
||||||
desc: "",
|
desc: "",
|
||||||
color: await getColors(
|
color: await getColors(`https://i.ytimg.com/vi/${v}/hqdefault.jpg?sqp=${this.sqp}`).then(colors => colors[0].hex()),
|
||||||
`https://i.ytimg.com/vi/${v}/hqdefault.jpg?sqp=${this.sqp}`
|
color2: await getColors(`https://i.ytimg.com/vi/${v}/hqdefault.jpg?sqp=${this.sqp}`).then(colors => colors[1].hex()),
|
||||||
).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(),
|
timestamp: Date.now(),
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.cache[v].result;
|
return this.cache[v].result;
|
||||||
} catch (error) {
|
|
||||||
this.initError("Error getting video", error);
|
|
||||||
}
|
}
|
||||||
}
|
} catch (error) {
|
||||||
} catch {
|
this.initError("Error getting video", error);
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
isvalidvideo(v) {
|
||||||
* Initialize an error.
|
if (v != "assets" && v != "cdn-cgi" && v != "404") {
|
||||||
* @param {string} args - Error message.
|
return /^([a-zA-Z0-9_-]{11})/.test(v);
|
||||||
* @param {Error} error - Error object.
|
}
|
||||||
*/
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
initError(args, error) {
|
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({
|
const pokeTubeApiCore = new InnerTubePokeVidious({
|
||||||
tubeApi: "https://inner-api.poketube.fun/api/",
|
tubeApi: "https://inner-api.poketube.fun/api/",
|
||||||
invapi: "https://invid-api.poketube.fun/bHj665PpYhUdPWuKPfZuQGoX/api/v1",
|
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",
|
invapi_alt: config.proxylocation === "EU" ? "https://invid-api.poketube.fun/api/v1" : "https://iv.ggtyler.dev/api/v1",
|
||||||
dislikes: "https://returnyoutubedislikeapi.com/votes?videoId=",
|
dislikes: "https://returnyoutubedislikeapi.com/votes?videoId=",
|
||||||
t_url: "https://t.poketube.fun/",
|
t_url: "https://t.poketube.fun/",
|
||||||
|
useragent: config.useragent,
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = pokeTubeApiCore;
|
module.exports = pokeTubeApiCore;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user