mirror of
https://codeberg.org/ashley/poke
synced 2025-06-20 12:32:11 +00:00
Compare commits
No commits in common. "dcf3b20fac627bf68f0a73384f012c571d032057" and "906f7b237eb4c76b9874a7c8a8ce4825a37a94a3" have entirely different histories.
dcf3b20fac
...
906f7b237e
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,4 +3,3 @@ yarn.lock
|
|||||||
package-lock.json
|
package-lock.json
|
||||||
.env
|
.env
|
||||||
json.sqlite
|
json.sqlite
|
||||||
config.json
|
|
@ -4,7 +4,6 @@
|
|||||||
"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 +1,33 @@
|
|||||||
(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 bbox = "?bbox=-165.76171875000003%2C-3.864254615721396%2C30.410156250000004%2C72.44879155730672&layer=mapnik"
|
||||||
|
var iframe = document.getElementById('myFrame');
|
||||||
|
iframe.src=`https://www.openstreetmap.org/export/embed.html${bbox}`
|
||||||
|
iframe.addEventListener('load', function() {
|
||||||
|
var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
|
||||||
|
var links = iframeDocument.getElementsByTagName('a');
|
||||||
|
for (var i = 0; i < links.length; i++) {
|
||||||
|
links[i].addEventListener('click', function(event) {
|
||||||
|
var url = event.target.href;
|
||||||
|
if (url.includes('www.openstreetmap.org')) {
|
||||||
|
event.preventDefault();
|
||||||
|
iframe.src = url;
|
||||||
|
window.history.pushState(null, '', url);
|
||||||
|
} else {
|
||||||
|
window.location.href = url;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
window.onpopstate = function(event) {
|
||||||
|
iframe.src = window.location.href;
|
||||||
|
};
|
||||||
|
|
||||||
|
iframe.addEventListener('load', function() {
|
||||||
|
var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
|
||||||
|
var elements = iframeDocument.querySelectorAll('[style*="//dka575ofm4ao0.cloudfront.net"]');
|
||||||
|
for (var i = 0; i < elements.length; i++) {
|
||||||
|
var style = elements[i].style.backgroundImage;
|
||||||
|
var newStyle = style.replace('//dka575ofm4ao0.cloudfront.net', 'https://p.poketube.fun/https://dka575ofm4ao0.cloudfront.net');
|
||||||
|
elements[i].style.backgroundImage = newStyle;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
2482
html/gamehub.ejs
2482
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-2025 Poke (https://codeberg.org/ashley/poke)
|
Copyright (C) 2021-2024 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 only (good) front-end in the world!" property=og:title>
|
<meta content="▶▶ Poke - The privacy app of your dreams!" property=og:title>
|
||||||
<% if(embedtype === "woke") { %>
|
<% if(embedtype === "woke") { %>
|
||||||
<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!!!"
|
<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!!!"
|
||||||
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, 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, 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!!!"
|
||||||
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;">THE ONLY FRONT-END IN THE WORLD!</h1>
|
<h1 style="text-align: center;">GUESS WHO'S BACK ...</h1>
|
||||||
<p style="max-width: 800px;text-align: center;margin: auto;margin-bottom: 3em;">Poke is a free software AD-FREE ! YouTube front-end, translator, map app, and more!!1! Watch videos and explore without a trace in this all-in-one privacy app!!1! :3</p>
|
<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>
|
||||||
<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,14 +152,11 @@
|
|||||||
<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: "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: "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: "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>" }
|
||||||
@ -191,6 +188,9 @@ const randomFeatures = features.sort(() => 0.5 - Math.random()).slice(0, 3);
|
|||||||
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',
|
||||||
|
@ -5,6 +5,9 @@
|
|||||||
<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....)") { %>
|
||||||
|
<meta http-equiv="refresh" content="5">
|
||||||
|
<% } %>
|
||||||
<link href="/css/yt-ukraine.svg?v=3" rel="icon" />
|
<link href="/css/yt-ukraine.svg?v=3" rel="icon" />
|
||||||
<link rel="manifest" href="/manifest.json" />
|
<link rel="manifest" href="/manifest.json" />
|
||||||
<style>
|
<style>
|
||||||
@ -78,66 +81,26 @@
|
|||||||
.error-footer a:hover {
|
.error-footer a:hover {
|
||||||
color: #d69cc8;
|
color: #d69cc8;
|
||||||
}
|
}
|
||||||
.countdown {
|
|
||||||
margin-top: 16px;
|
|
||||||
color: #ccc;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
</style>
|
</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) {
|
|
||||||
location.reload();
|
|
||||||
} else {
|
|
||||||
seconds--;
|
|
||||||
setTimeout(updateCountdown, 1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
window.addEventListener('DOMContentLoaded', updateCountdown);
|
|
||||||
</script>
|
|
||||||
<% } else { %>
|
|
||||||
<script>
|
|
||||||
// Clear reload count on non-restart errors
|
|
||||||
localStorage.removeItem('reloadCount');
|
|
||||||
</script>
|
|
||||||
<% } %>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<% if (description === RESTART_MSG) { %>
|
<% if (description == "This helps protect our community. Learn more (TRYING AGAIN....)") { %>
|
||||||
|
|
||||||
<p id="abstract">502</p>
|
<p id="abstract">502</p>
|
||||||
<% } else { %>
|
<% } else if (description !== "This helps protect our community. Learn more (TRYING AGAIN....)") { %>
|
||||||
<p id="abstract">404</p>
|
<p id="abstract">404</p>
|
||||||
|
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
<div class="error">
|
<div class="error">
|
||||||
<h2><%=error%></h2>
|
<h2><%=error%></h2>
|
||||||
<p><%=description%></p>
|
<p><%=description%></p>
|
||||||
<% if (description === RESTART_MSG) { %>
|
|
||||||
<div class="countdown" id="countdown"></div>
|
|
||||||
<% } %>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="error-footer">
|
<div class="error-footer">
|
||||||
<a href="https://codeberg.org/ashley/poke/issues/new/choose">Create issue</a>
|
<a href="https://codeberg.org/ashley/poke/issues/new/choose">Create issue</a>
|
||||||
<a href="https://discord.poketube.fun">Report on our Discord</a>
|
<a href="https://discord.poketube.fun">Report on our Discord</a>
|
||||||
<% if (description === RESTART_MSG) { %>
|
<% if (description == "This helps protect our community. Learn more (TRYING AGAIN....)") { %>
|
||||||
|
|
||||||
<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>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
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-2025 POKETUBE (https://github.com/iamashley0/poketube)
|
* Copyright (C) 2021-2023 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,178 +44,6 @@
|
|||||||
|
|
||||||
//--><!]]>
|
//--><!]]>
|
||||||
</script>
|
</script>
|
||||||
<script>(function(){
|
<script src="/static/maps.js"></script><script src="/static/data-mobile.js"></script>
|
||||||
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,6 +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>
|
||||||
|
488
html/search.ejs
488
html/search.ejs
@ -424,10 +424,7 @@ video[counter].classList.add("shake");
|
|||||||
</div> </div>
|
</div> </div>
|
||||||
|
|
||||||
|
|
||||||
<div class=right style="background: #333;
|
<div class=right>
|
||||||
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>
|
||||||
@ -455,7 +452,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;margin-top: 6px;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;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"; %>
|
||||||
@ -497,8 +494,7 @@ video[counter].classList.add("shake");
|
|||||||
<% }) %>
|
<% }) %>
|
||||||
|
|
||||||
</div> </fieldset></div>
|
</div> </fieldset></div>
|
||||||
<br> <div id="filters-apply">
|
<br> <div id="filters-apply"> <button type="submit" style="color:#fff;background:#333;padding:3px;border-radius:11px;margin-top: 6em;">Apply!</button></div>
|
||||||
<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>
|
||||||
@ -515,20 +511,21 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (/^[0-9\s+\-*/.x]+$/.test(query)) {
|
function evaluateMathExpression(expression) {
|
||||||
const expr = query.replace(/\s+/g, '');
|
// twenyone
|
||||||
answer = expr === '9+10' ? '21' : (() => {
|
if (expression.replace(/\s+/g, '') === '9+10') {
|
||||||
try { return eval(expr); } catch { return 'Invalid Expression'; }
|
return '21';
|
||||||
})();
|
}
|
||||||
return answer;
|
|
||||||
|
try {
|
||||||
|
return eval(expression);
|
||||||
|
} catch (error) {
|
||||||
|
return 'Invalid Expression';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCurrentDate() {
|
function getCurrentDate() {
|
||||||
@ -541,7 +538,7 @@ function getCurrentYear() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getTimeInTimezone(location) {
|
function getTimeInTimezone(location) {
|
||||||
const tzMap = {
|
const timezones = {
|
||||||
"california": "America/Los_Angeles",
|
"california": "America/Los_Angeles",
|
||||||
"new york": "America/New_York",
|
"new york": "America/New_York",
|
||||||
"chicago": "America/Chicago",
|
"chicago": "America/Chicago",
|
||||||
@ -571,7 +568,9 @@ const tzMap = {
|
|||||||
"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",
|
||||||
|
"lahore": "Asia/Karachi",
|
||||||
"dubai": "Asia/Dubai",
|
"dubai": "Asia/Dubai",
|
||||||
"abu dhabi": "Asia/Dubai",
|
"abu dhabi": "Asia/Dubai",
|
||||||
"riyadh": "Asia/Riyadh",
|
"riyadh": "Asia/Riyadh",
|
||||||
@ -587,92 +586,10 @@ const tzMap = {
|
|||||||
"vienna": "Europe/Vienna",
|
"vienna": "Europe/Vienna",
|
||||||
"stockholm": "Europe/Stockholm",
|
"stockholm": "Europe/Stockholm",
|
||||||
"oslo": "Europe/Oslo",
|
"oslo": "Europe/Oslo",
|
||||||
"helsinki": "Europe/Helsinki",
|
"helsinki": "Europe/Helsinki"
|
||||||
"prague": "Europe/Prague",
|
|
||||||
"budapest": "Europe/Budapest",
|
|
||||||
"warsaw": "Europe/Warsaw",
|
|
||||||
"bucharest": "Europe/Bucharest",
|
|
||||||
"sofia": "Europe/Sofia",
|
|
||||||
"zagreb": "Europe/Zagreb",
|
|
||||||
"belgrade": "Europe/Belgrade",
|
|
||||||
"sarajevo": "Europe/Sarajevo",
|
|
||||||
"podgorica": "Europe/Podgorica",
|
|
||||||
"ljubljana": "Europe/Ljubljana",
|
|
||||||
"tirana": "Europe/Tirane",
|
|
||||||
"valletta": "Europe/Malta",
|
|
||||||
"andorra la vella": "Europe/Andorra",
|
|
||||||
"monaco": "Europe/Monaco",
|
|
||||||
"luxembourg": "Europe/Luxembourg",
|
|
||||||
"bratislava": "Europe/Bratislava",
|
|
||||||
"vilnius": "Europe/Vilnius",
|
|
||||||
"riga": "Europe/Riga",
|
|
||||||
"tallinn": "Europe/Tallinn",
|
|
||||||
"istanbul": "Europe/Istanbul",
|
|
||||||
"jerusalem": "Asia/Jerusalem",
|
|
||||||
"amman": "Asia/Amman",
|
|
||||||
"beirut": "Asia/Beirut",
|
|
||||||
"damascus": "Asia/Damascus",
|
|
||||||
"baghdad": "Asia/Baghdad",
|
|
||||||
"tehran": "Asia/Tehran",
|
|
||||||
"islamabad": "Asia/Karachi",
|
|
||||||
"kathmandu": "Asia/Kathmandu",
|
|
||||||
"thimphu": "Asia/Thimphu",
|
|
||||||
"dhaka": "Asia/Dhaka",
|
|
||||||
"yangon": "Asia/Yangon",
|
|
||||||
"hanoi": "Asia/Ho_Chi_Minh",
|
|
||||||
"ho chi minh city": "Asia/Ho_Chi_Minh",
|
|
||||||
"manila": "Asia/Manila",
|
|
||||||
"singapore": "Asia/Singapore",
|
|
||||||
"kuala lumpur": "Asia/Kuala_Lumpur",
|
|
||||||
"colombo": "Asia/Colombo",
|
|
||||||
"bagotville": "America/Montreal",
|
|
||||||
"toronto": "America/Toronto",
|
|
||||||
"vancouver": "America/Vancouver",
|
|
||||||
"mexico city": "America/Mexico_City",
|
|
||||||
"guadalajara": "America/Mexico_City",
|
|
||||||
"monterrey": "America/Monterrey",
|
|
||||||
"sao paulo": "America/Sao_Paulo",
|
|
||||||
"buenos aires": "America/Argentina/Buenos_Aires",
|
|
||||||
"santiago": "America/Santiago",
|
|
||||||
"rio de janeiro": "America/Sao_Paulo",
|
|
||||||
"caracas": "America/Caracas",
|
|
||||||
"bogota": "America/Bogota",
|
|
||||||
"lima": "America/Lima",
|
|
||||||
"quito": "America/Quito",
|
|
||||||
"georgetown": "America/Guyana",
|
|
||||||
"paramaribo": "America/Paramaribo",
|
|
||||||
"cayenne": "America/Cayenne",
|
|
||||||
"kingston": "America/Jamaica",
|
|
||||||
"port_of_spain": "America/Port_of_Spain",
|
|
||||||
"st johns": "America/St_Johns",
|
|
||||||
"midway": "Pacific/Midway",
|
|
||||||
"apia": "Pacific/Apia",
|
|
||||||
"nuku alofa": "Pacific/Tongatapu",
|
|
||||||
"tarawa": "Pacific/Tarawa",
|
|
||||||
"funafuti": "Pacific/Funafuti",
|
|
||||||
"suva": "Pacific/Fiji",
|
|
||||||
"chatham": "Pacific/Chatham",
|
|
||||||
"pitcairn": "Pacific/Pitcairn",
|
|
||||||
"galapagos": "Pacific/Galapagos",
|
|
||||||
"easter island": "Pacific/Easter",
|
|
||||||
"honiara": "Pacific/Guadalcanal",
|
|
||||||
"port vila": "Pacific/Efate",
|
|
||||||
"palikir": "Pacific/Pohnpei",
|
|
||||||
"palau": "Pacific/Palau",
|
|
||||||
"mcmurdo": "Antarctica/McMurdo",
|
|
||||||
"rothera": "Antarctica/Rothera",
|
|
||||||
"troll": "Antarctica/Troll",
|
|
||||||
"davis": "Antarctica/Davis",
|
|
||||||
"casey": "Antarctica/Casey",
|
|
||||||
"mawson": "Antarctica/Mawson",
|
|
||||||
"vostok": "Antarctica/Vostok",
|
|
||||||
"syowa": "Antarctica/Syowa",
|
|
||||||
"gmt": "Etc/GMT",
|
|
||||||
"utc": "UTC"
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const timezone = timezones[location.toLowerCase()];
|
||||||
const timezone = tzMap[location.toLowerCase()];
|
|
||||||
if (!timezone) {
|
if (!timezone) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -682,186 +599,9 @@ const tzMap = {
|
|||||||
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')) {
|
||||||
@ -878,70 +618,17 @@ 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')
|
answer = query.includes('girl') ? "yesh :3 u are a good girl" : "yesh :3 u are a good boy";
|
||||||
? "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?'",
|
||||||
"[new] Ask 'What's the date today?'",
|
"[new] Ask 'What's the date today?'",
|
||||||
@ -966,110 +653,31 @@ function extractQueryFromUpsellMessage(message) {
|
|||||||
%>
|
%>
|
||||||
%>
|
%>
|
||||||
<% if (answer) { %>
|
<% if (answer) { %>
|
||||||
<div class="container" style="padding: 1em;">
|
<div class="container">
|
||||||
<h2 style="font-family: 'PokeTube Flex';font-size: large;text-align: left !important;font-stretch: ultra-expanded; font-weight: 1000; margin-bottom: -0.1em;">
|
<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;">
|
<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>
|
||||||
<i title="PokeIntellagance!" class="fa-light fa-sparkles"></i>
|
<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>
|
||||||
</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 -->
|
||||||
<%
|
<%
|
||||||
@ -1410,12 +1018,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: 8px;">
|
<a href="/download?v=<%= x.videoId %>" style="background: #333;width: 7.6em;border-radius: 18px;">
|
||||||
<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: 8px;height: 2em;width: 12.5em;">
|
<a href="https://youtube.com/watch?v=<%= x.videoId %>" style="background: #333;width: 7.6em;border-radius: 18px;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>
|
||||||
@ -1447,12 +1055,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: 8px;">
|
<a href="/download?v=<%= x.videoId %>" style="background: #333;width: 7.6em;border-radius: 18px;">
|
||||||
<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: 8px;height: 2em;width: 12.5em;">
|
<a href="https://youtube.com/watch?v=<%= x.videoId %>" style="background: #333;width: 7.6em;border-radius: 18px;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,6 +16,172 @@
|
|||||||
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>
|
||||||
|
<title>PokeTranslate</title>
|
||||||
|
<link rel="icon" href="/static/yt-ukraine.svg">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta content="PokeTranslate" property=og:title>
|
||||||
|
<meta content="Translate text - Anonymously!" property=twitter:description>
|
||||||
|
<meta content="https://cdn.glitch.global/d68d17bb-f2c0-4bc3-993f-50902734f652/aa70111e-5bcd-4379-8b23-332a33012b78.image.png?v=1701898829884" property="og:image" />
|
||||||
|
<meta content=summary_large_image name=twitter:card>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline'">
|
||||||
|
<meta name="referrer" content="no-referrer">
|
||||||
|
<link rel="manifest" href="/manifest.json">
|
||||||
|
<style>
|
||||||
|
.center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrap {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrap.languages {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
width: 100%;
|
||||||
|
height: 150px;
|
||||||
|
border-radius: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-wrapper {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
width: 450px;
|
||||||
|
margin: 5px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
select,
|
||||||
|
input,
|
||||||
|
textarea {
|
||||||
|
border-radius: 1em;
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #131618;
|
||||||
|
border: 2px solid #495057;
|
||||||
|
color: #f8f9fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
justify-content: center;
|
||||||
|
font-family: sans-serif;
|
||||||
|
background-color: #2c2f33;
|
||||||
|
color: #f8f9fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
#translation-form {
|
||||||
|
background-color: #1f2023;
|
||||||
|
border-radius: 1em;
|
||||||
|
padding: 20px;
|
||||||
|
width: 90%;
|
||||||
|
max-width: 800px;
|
||||||
|
margin: auto;
|
||||||
|
box-shadow: 0 0 15px rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
color: #5bc0de;
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#definitions_and_translations {
|
||||||
|
display: grid;
|
||||||
|
width: 100%;
|
||||||
|
grid-template-areas: "definitions translations";
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 1200px) {
|
||||||
|
#definitions_and_translations {
|
||||||
|
display: grid;
|
||||||
|
grid-template-areas:
|
||||||
|
"definitions definitions"
|
||||||
|
"translations translations";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div.definitions,
|
||||||
|
div.translations {
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #3a3f44;
|
||||||
|
border-radius: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea:focus,
|
||||||
|
input:focus,
|
||||||
|
button:focus {
|
||||||
|
border-color: #478061;
|
||||||
|
outline: 1px solid #478061;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #599bf6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Additional styles to match the calendar page */
|
||||||
|
header {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#switchbutton {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center button {
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive design */
|
||||||
|
@media screen and (max-width: 768px) {
|
||||||
|
#translation-form {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrap {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<% if (isMobile) { %>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
|
<% if (!isMobile) { %>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<% } %>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="translation-form">
|
||||||
|
<header class="center">
|
||||||
|
<h1>PokeTranslate</h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
<% const languageOptions = [
|
<% const languageOptions = [
|
||||||
{ code: 'autodetect', name: 'Autodetect' },
|
{ code: 'autodetect', name: 'Autodetect' },
|
||||||
@ -113,284 +279,70 @@
|
|||||||
{ code: 'yo', name: 'Yoruba' },
|
{ code: 'yo', name: 'Yoruba' },
|
||||||
{ code: 'zu', name: 'Zulu' }
|
{ code: 'zu', name: 'Zulu' }
|
||||||
]; %>
|
]; %>
|
||||||
|
<form action="/translate" method="GET" id="translation-form">
|
||||||
<!doctype html>
|
<!-- from and to language -->
|
||||||
<html lang="en">
|
<div class="wrap languages">
|
||||||
<head>
|
<div class="language">
|
||||||
<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">
|
<select name="from_language" id="from_language">
|
||||||
<% languageOptions.forEach(lang => { %>
|
<% languageOptions.forEach(language => { %>
|
||||||
<option value="<%= lang.code %>" <%= lang.code === (from_language||'autodetect')?'selected':''%>>
|
<option value="<%= language.code %>" <%= language.code === (from_language || 'autodetect') ? 'selected' : '' %>>
|
||||||
<%= lang.name %>
|
<%= language.name %>
|
||||||
</option>
|
</option>
|
||||||
<% }); %>
|
<% }); %>
|
||||||
</select>
|
</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">
|
<select name="to_language" id="to_language">
|
||||||
<% languageOptions.slice(1).forEach(lang => { %>
|
<% languageOptions.slice(1).forEach(language => { %>
|
||||||
<option value="<%= lang.code %>" <%= lang.code===to_language?'selected':''%>>
|
<option value="<%= language.code %>" <%= language.code === to_language ? 'selected' : '' %>>
|
||||||
<%= lang.name %>
|
<%= language.name %>
|
||||||
</option>
|
</option>
|
||||||
<% }); %>
|
<% }); %>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="panels">
|
<!-- text boxes -->
|
||||||
<div class="panel input">
|
<div class="wrap">
|
||||||
<label for="input">Input</label>
|
<div class="item-wrapper">
|
||||||
<textarea id="input" name="input" placeholder="Enter text…"><%= text %></textarea>
|
<textarea autofocus class="item" id="input" name="input" dir="auto" placeholder="<%- text %>">
|
||||||
|
<%- text %>
|
||||||
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel output">
|
|
||||||
<label for="output">Translation</label>
|
<div class="item-wrapper">
|
||||||
<textarea id="output" readonly placeholder="Translated text…"><%= translation %></textarea>
|
<textarea id="output" class="translation item" dir="auto" placeholder="Translation" readonly>
|
||||||
|
<%- translation %>
|
||||||
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="actions">
|
<div class="center">
|
||||||
<button type="submit">Translate :3</button>
|
<button type="submit">Translate :3</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
(function(){
|
document.getElementById("input").addEventListener("keydown", function (event) {
|
||||||
// swap button
|
if (event.keyCode === 13 && (event.metaKey || event.ctrlKey)) {
|
||||||
const swapBtn = document.getElementById('swapBtn');
|
document.getElementById("translation-form").submit();
|
||||||
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
|
var input = document.getElementById("input");
|
||||||
if(window.fetch){
|
var output = document.getElementById("output");
|
||||||
const from = document.getElementById('from_language');
|
input.setAttribute("style", "height:" + output.scrollHeight + "px;overflow-y:scroll;");
|
||||||
const to = document.getElementById('to_language');
|
output.setAttribute("style", "height:" + output.scrollHeight + "px;overflow-y:scroll;");
|
||||||
const input = document.getElementById('input');
|
input.addEventListener("input", function (e) {
|
||||||
const output= document.getElementById('output');
|
this.style.height = 150 + "px";
|
||||||
let timer;
|
this.style.height = this.scrollHeight + "px";
|
||||||
|
|
||||||
function translateNow(){
|
|
||||||
const q = new URLSearchParams({
|
|
||||||
from_language: from.value,
|
|
||||||
to_language: to.value,
|
|
||||||
input: input.value
|
|
||||||
});
|
});
|
||||||
fetch(`/translate?${q}`)
|
|
||||||
.then(r => r.text())
|
|
||||||
.then(html => {
|
|
||||||
const doc = new DOMParser().parseFromString(html, 'text/html');
|
|
||||||
const newOut = doc.getElementById('output');
|
|
||||||
if(newOut){
|
|
||||||
output.value = newOut.value;
|
|
||||||
output.dispatchEvent(new Event('input'));
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(() => {/* ignore */});
|
|
||||||
}
|
|
||||||
|
|
||||||
// debounce on typing
|
|
||||||
input.addEventListener('input', ()=>{
|
|
||||||
clearTimeout(timer);
|
|
||||||
timer = setTimeout(translateNow, 500);
|
|
||||||
});
|
|
||||||
// re-translate on language change
|
|
||||||
from.addEventListener('change', translateNow);
|
|
||||||
to.addEventListener('change', translateNow);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
</script>
|
</script>
|
||||||
|
<script src="/static/custom-css.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</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 = "Poke is currently restarting - please wait 1-2 minutes..";
|
reason = "This helps protect our community. Learn more (TRYING AGAIN....)";
|
||||||
}
|
}
|
||||||
%>
|
%>
|
||||||
|
|
||||||
|
@ -967,7 +967,6 @@ Offical Discord Server! :3
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<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>
|
<a href="/app" class="account"><i class="fa-light fa-compass"></i>Discover!</a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -1025,7 +1024,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" />
|
<source src="<%=u%>/latest_version?id=<%=inv_vid.videoId%>&itag=<%=itag%>&local=true" type="video/mp4" onerror="setTimeout(function() { location.reload(); }, 5000);" />
|
||||||
</audio>
|
</audio>
|
||||||
<% } else { %>
|
<% } else { %>
|
||||||
<audio id="aud"></audio>
|
<audio id="aud"></audio>
|
||||||
@ -1039,7 +1038,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>
|
<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);">
|
||||||
<% if (isvidious) { %>
|
<% if (isvidious) { %>
|
||||||
<% if (!qua) { %>
|
<% if (!qua) { %>
|
||||||
<%
|
<%
|
||||||
@ -1050,10 +1049,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">
|
<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);">
|
||||||
<% } %>
|
<% } %>
|
||||||
<% 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" >
|
<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);"">
|
||||||
<% } %>
|
<% } %>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
@ -1784,7 +1783,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> <% } %> </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> <% }) %>
|
<% 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><% }) %>
|
||||||
<center>
|
<center>
|
||||||
<a href="#top">Go To Top</a>
|
<a href="#top">Go To Top</a>
|
||||||
</center>
|
</center>
|
||||||
@ -1838,6 +1837,12 @@ 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) { %>
|
||||||
|
|
||||||
@ -2570,6 +2575,12 @@ 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">
|
||||||
|
|
||||||
|
<% } %>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -2910,9 +2921,6 @@ 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": "^13.4.0"
|
"youtubei.js": "^9.3.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
|
@ -23,6 +23,7 @@ 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!",
|
||||||
@ -130,7 +131,10 @@ const splash = [
|
|||||||
"stallmansupport.org!!!",
|
"stallmansupport.org!!!",
|
||||||
"does include nya~!!!",
|
"does include nya~!!!",
|
||||||
"actually stable! :3",
|
"actually stable! :3",
|
||||||
];
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function getJson(str) {
|
function getJson(str) {
|
||||||
try {
|
try {
|
||||||
@ -149,16 +153,13 @@ module.exports = function (app, config, renderTemplate) {
|
|||||||
tab = `/?type=${capitalizeFirstLetter(req.query.tab)}`;
|
tab = `/?type=${capitalizeFirstLetter(req.query.tab)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const invtrend = await fetch(`${config.invapi}/trending${tab}`, {
|
const invtrend = await fetch(
|
||||||
headers: { "User-Agent": config.useragent },
|
`${config.invapi}/trending${tab}`
|
||||||
});
|
);
|
||||||
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());
|
||||||
|
|
||||||
@ -189,15 +190,18 @@ 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 =
|
const isOldWindows = (uaos === "Windows 7" || uaos === "Windows 8") && browser === "Firefox";
|
||||||
(uaos === "Windows 7" || uaos === "Windows 8") &&
|
|
||||||
browser === "Firefox";
|
|
||||||
var proxyurl = config.p_url;
|
var proxyurl = config.p_url;
|
||||||
|
|
||||||
const secure = ["poketube.fun", "localhost"].includes(req.hostname);
|
const secure = [
|
||||||
const verify = ["poketube.fun", "poke.ashley0143.xyz", "localhost"].includes(
|
"poketube.fun",
|
||||||
req.hostname
|
"localhost" //
|
||||||
);
|
].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) {
|
||||||
@ -212,7 +216,7 @@ module.exports = function (app, config, renderTemplate) {
|
|||||||
verify,
|
verify,
|
||||||
isOldWindows,
|
isOldWindows,
|
||||||
proxyurl,
|
proxyurl,
|
||||||
random,
|
random
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -221,10 +225,10 @@ 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
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,22 @@
|
|||||||
const { modules } = require("../libpoketube-initsys.js");
|
const {
|
||||||
|
fetcher,
|
||||||
|
core,
|
||||||
|
wiki,
|
||||||
|
musicInfo,
|
||||||
|
modules,
|
||||||
|
version,
|
||||||
|
initlog,
|
||||||
|
init,
|
||||||
|
} = require("../libpoketube-initsys.js");
|
||||||
|
const {
|
||||||
|
IsJsonString,
|
||||||
|
convert,
|
||||||
|
getFirstLine,
|
||||||
|
capitalizeFirstLetter,
|
||||||
|
turntomins,
|
||||||
|
getRandomInt,
|
||||||
|
getRandomArbitrary,
|
||||||
|
} = require("../ptutils/libpt-coreutils.js");
|
||||||
|
|
||||||
var http = require("https");
|
var http = require("https");
|
||||||
var ping = require("ping");
|
var ping = require("ping");
|
||||||
|
@ -1,4 +1,22 @@
|
|||||||
const { modules, version } = require("../libpoketube-initsys.js");
|
const {
|
||||||
|
fetcher,
|
||||||
|
core,
|
||||||
|
wiki,
|
||||||
|
musicInfo,
|
||||||
|
modules,
|
||||||
|
version,
|
||||||
|
initlog,
|
||||||
|
init,
|
||||||
|
} = require("../libpoketube-initsys.js");
|
||||||
|
const {
|
||||||
|
IsJsonString,
|
||||||
|
convert,
|
||||||
|
getFirstLine,
|
||||||
|
capitalizeFirstLetter,
|
||||||
|
turntomins,
|
||||||
|
getRandomInt,
|
||||||
|
getRandomArbitrary,
|
||||||
|
} = require("../ptutils/libpt-coreutils.js");
|
||||||
|
|
||||||
function getJson(str) {
|
function getJson(str) {
|
||||||
try {
|
try {
|
||||||
@ -11,35 +29,29 @@ 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 { execSync } = require('child_process'); // DO NOT ABBRV THIS :SOB:
|
const verfull = "v24.1906-sho-MAJOR_UPDATE-stable-dev-nonLTS-git-MTcxODc5NDY3NQ==";
|
||||||
|
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 = "luna";
|
const codename = "sho";
|
||||||
const versionnumber = "294";
|
const versionnumber = "293";
|
||||||
const relaseunixdate = "MTc0NTcwNjc4MA==";
|
const relaseunixdate = "MTcxODc5NDY3NQ=="
|
||||||
const updatequote = "i created this world.....to feel some control...";
|
const updatequote = "pls fund vennie plush -Bims"
|
||||||
|
|
||||||
|
|
||||||
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) {
|
||||||
@ -47,7 +59,6 @@ module.exports = function (app, config, renderTemplate) {
|
|||||||
|
|
||||||
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);
|
||||||
@ -58,30 +69,39 @@ module.exports = function (app, config, renderTemplate) {
|
|||||||
|
|
||||||
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;
|
||||||
|
|
||||||
var q = "18";
|
var q = "18";
|
||||||
if (req.query.q) q = req.query.q;
|
if (req.query.q) q = req.query.q;
|
||||||
|
|
||||||
const url = `${config.videourl}latest_version?id=${v}&itag=${q}&local=true`;
|
const url = `https://eu-proxy.poketube.fun/latest_version?id=${v}&itag=${q}&local=true`;
|
||||||
|
|
||||||
res.redirect(url);
|
res.redirect(url);
|
||||||
});
|
});
|
||||||
@ -93,12 +113,9 @@ module.exports = function (app, config, renderTemplate) {
|
|||||||
const l = req.query.h;
|
const l = req.query.h;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let url = `${config.videourl}/api/v1/captions/${id}?label=${l}`;
|
let url = `https://eu-proxy.poketube.fun/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);
|
||||||
@ -114,9 +131,7 @@ module.exports = function (app, config, renderTemplate) {
|
|||||||
if (id) {
|
if (id) {
|
||||||
const apiUrl = `https://ryd-proxy.kavin.rocks/votes/${id}&hash=d0550b6e28c8f93533a569c314d5b4e2`;
|
const apiUrl = `https://ryd-proxy.kavin.rocks/votes/${id}&hash=d0550b6e28c8f93533a569c314d5b4e2`;
|
||||||
|
|
||||||
const response = await fetch(apiUrl, {
|
const response = await fetch(apiUrl);
|
||||||
headers: headers,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.status === 400) {
|
if (response.status === 400) {
|
||||||
const error = await response.json();
|
const error = await response.json();
|
||||||
@ -209,6 +224,48 @@ module.exports = function (app, config, renderTemplate) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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 id = req.query.v;
|
||||||
|
const l = req.query.h;
|
||||||
|
|
||||||
|
try {
|
||||||
|
let url = `https://yt.miruku.cafe/api/v1/storyboards/${id}?width=320&height=180`;
|
||||||
|
|
||||||
|
let f = await fetch(url);
|
||||||
|
let body = await f.text();
|
||||||
|
|
||||||
|
body = body.replace(/#xywh=(\d+),(\d+),(\d+),(\d+)/g, (match, x, y, w, h) => {
|
||||||
|
return `&xywh=${x},${y},${w},${h}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
res.send(body);
|
||||||
|
} catch {}
|
||||||
|
});
|
||||||
|
|
||||||
app.get("/feeds/videos.xml", async (req, res) => {
|
app.get("/feeds/videos.xml", async (req, res) => {
|
||||||
const id = req.query.channel_id;
|
const id = req.query.channel_id;
|
||||||
|
|
||||||
@ -216,7 +273,6 @@ module.exports = function (app, config, renderTemplate) {
|
|||||||
|
|
||||||
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);
|
||||||
@ -229,12 +285,13 @@ module.exports = function (app, config, renderTemplate) {
|
|||||||
|
|
||||||
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);
|
||||||
|
|
||||||
@ -257,9 +314,7 @@ module.exports = function (app, config, renderTemplate) {
|
|||||||
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));
|
||||||
|
|
||||||
@ -275,20 +330,19 @@ module.exports = function (app, config, renderTemplate) {
|
|||||||
|
|
||||||
latestCommitHash = stdout.trim();
|
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: configWithoutUA,
|
config:cnf,
|
||||||
system:{
|
system:{
|
||||||
ram:`${roundedMemory} GB`,
|
ram:`${roundedMemory} GB`,
|
||||||
cpu:cpus[0].model,
|
cpu:cpus[0].model,
|
||||||
@ -320,9 +374,7 @@ const { useragent, ...configWithoutUA } = cnf;
|
|||||||
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));
|
||||||
|
|
||||||
|
@ -135,6 +135,7 @@ 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");
|
||||||
}
|
}
|
||||||
@ -159,14 +160,11 @@ module.exports = function (app, config, renderTemplate) {
|
|||||||
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, {
|
const xmlData = await fetch(searchUrl)
|
||||||
headers: {
|
|
||||||
'User-Agent': config.useragent,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.then((res) => res.text())
|
.then((res) => res.text())
|
||||||
.then((txt) => getJson(txt));
|
.then((txt) => getJson(txt));
|
||||||
|
|
||||||
|
|
||||||
renderTemplate(res, req, "search.ejs", {
|
renderTemplate(res, req, "search.ejs", {
|
||||||
invresults: xmlData,
|
invresults: xmlData,
|
||||||
turntomins,
|
turntomins,
|
||||||
@ -220,11 +218,7 @@ module.exports = function (app, config, renderTemplate) {
|
|||||||
|
|
||||||
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 {
|
||||||
@ -244,11 +238,7 @@ module.exports = function (app, config, renderTemplate) {
|
|||||||
|
|
||||||
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) {
|
||||||
@ -290,6 +280,7 @@ module.exports = function (app, config, renderTemplate) {
|
|||||||
getChannelData(channelINVUrl),
|
getChannelData(channelINVUrl),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
var bannedchannels = ["UC1okSIA8UEY8OqvtjGHFvzA", "UClsVg5LkK2COQRo1mVS4taA", "UCIr4vkCsn0tdTW2xZ1jRG1g"];
|
var bannedchannels = ["UC1okSIA8UEY8OqvtjGHFvzA", "UClsVg5LkK2COQRo1mVS4taA", "UCIr4vkCsn0tdTW2xZ1jRG1g"];
|
||||||
var bypassQuery = "cG9rZXR1YmVjaGFubmVsYnlwYXNzbG9scGVvcGxldGhpbmt0aGlzaXNjZW5zb3JzaGlwLTQ1OTBh";
|
var bypassQuery = "cG9rZXR1YmVjaGFubmVsYnlwYXNzbG9scGVvcGxldGhpbmt0aGlzaXNjZW5zb3JzaGlwLTQ1OTBh";
|
||||||
|
|
||||||
@ -297,11 +288,14 @@ module.exports = function (app, config, renderTemplate) {
|
|||||||
var tabExists = 'tab' in req.query;
|
var tabExists = 'tab' in req.query;
|
||||||
var continuationExists = 'continuation' in req.query;
|
var continuationExists = 'continuation' in req.query;
|
||||||
|
|
||||||
|
|
||||||
if (bannedchannels.some(channel => channel === ID) && !bypassExists && !tabExists && !continuationExists) {
|
if (bannedchannels.some(channel => channel === ID) && !bypassExists && !tabExists && !continuationExists) {
|
||||||
var cinv = {
|
var cinv = {
|
||||||
error:`this channel may include disinformation. If you still wanna view content <a href="/channel?id=${ID}&bypass=${bypassQuery}">click here</a> to bypass this restriction.`
|
error:`this channel may include disinformation. If you still wanna view content <a href="/channel?id=${ID}&bypass=${bypassQuery}">click here</a> to bypass this restriction.`
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function getThumbnailUrl(video) {
|
function getThumbnailUrl(video) {
|
||||||
const maxresDefaultThumbnail = video.videoThumbnails.find(
|
const maxresDefaultThumbnail = video.videoThumbnails.find(
|
||||||
@ -339,6 +333,8 @@ module.exports = function (app, config, renderTemplate) {
|
|||||||
);
|
);
|
||||||
const dnoreplace = about?.Description.toString();
|
const dnoreplace = about?.Description.toString();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let ChannelFirstVideoObject = {
|
let ChannelFirstVideoObject = {
|
||||||
subCountText: "0",
|
subCountText: "0",
|
||||||
authorVerified: false,
|
authorVerified: false,
|
||||||
@ -367,7 +363,8 @@ module.exports = function (app, config, renderTemplate) {
|
|||||||
isMobile: req.useragent.isMobile,
|
isMobile: req.useragent.isMobile,
|
||||||
about,
|
about,
|
||||||
playlist,
|
playlist,
|
||||||
subs: typeof subscribers === "string"
|
subs:
|
||||||
|
typeof subscribers === "string"
|
||||||
? subscribers.replace("subscribers", "")
|
? subscribers.replace("subscribers", "")
|
||||||
: "None",
|
: "None",
|
||||||
desc: dnoreplace === "[object Object]" ? "" : description,
|
desc: dnoreplace === "[object Object]" ? "" : description,
|
||||||
|
@ -115,22 +115,27 @@ 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");
|
||||||
});
|
});
|
||||||
|
|
||||||
const headers = { "User-Agent": config.useragent };
|
|
||||||
|
|
||||||
app.get("/playlist", async function (req, res) {
|
app.get("/playlist", async function (req, res) {
|
||||||
|
const { fetch } = await import("undici");
|
||||||
if (!req.query.list) res.redirect("/");
|
if (!req.query.list) res.redirect("/");
|
||||||
if (req.useragent.isMobile) res.redirect("/");
|
if (req.useragent.isMobile) res.redirect("/");
|
||||||
const playlist = await fetch(`${config.invapi}/playlists/${req.query.list}?hl=en-us`, { headers });
|
|
||||||
|
const playlist = await fetch(
|
||||||
|
`${config.invapi}/playlists/${req.query.list}?hl=en-us`
|
||||||
|
);
|
||||||
|
|
||||||
const p = getJson(await playlist.text());
|
const p = getJson(await playlist.text());
|
||||||
var mediaproxy = config.media_proxy;
|
var mediaproxy = config.media_proxy;
|
||||||
|
|
||||||
if (req.useragent.source.includes("Pardus")) {
|
if (req.useragent.source.includes("Pardus")) {
|
||||||
mediaproxy = "https://media-proxy.ashley0143.xyz";
|
var mediaproxy = "https://media-proxy.ashley0143.xyz";
|
||||||
}
|
}
|
||||||
renderTemplate(res, req, "playlist.ejs", { p, mediaproxy });
|
|
||||||
|
renderTemplate(res, req, "playlist.ejs", {
|
||||||
|
p,
|
||||||
|
mediaproxy,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
app.get("/license", function (req, res) {
|
app.get("/license", function (req, res) {
|
||||||
renderTemplate(res, req, "license.ejs");
|
renderTemplate(res, req, "license.ejs");
|
||||||
@ -256,7 +261,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", "breakout", "minesweeper"];
|
var gameslist = ["pong", "tic-tac-toe", "sudoku", "snake"];
|
||||||
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 = config.videourl;
|
var vidurl = "https://eu-proxy.poketube.fun";
|
||||||
var isvidious = true;
|
var isvidious = true;
|
||||||
|
|
||||||
if (req.useragent.source.includes("Pardus")) {
|
if (req.useragent.source.includes("Pardus")) {
|
||||||
|
@ -12,7 +12,20 @@ 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 = {};
|
||||||
@ -23,12 +36,17 @@ 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 = config.useragent || "PokeTube/2.0.0 (GNU/Linux; Android 14; Trisquel 11; poketube-vidious; like FreeTube)"
|
this.useragent = "com.google.android.youtube/19.14.42 (Linux; U; Android 12; US) gzip"
|
||||||
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);
|
||||||
@ -37,68 +55,92 @@ 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) {
|
||||||
return obj && "authorId" in obj;
|
if (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 = {};
|
||||||
|
|
||||||
const headers = {
|
let desc = "";
|
||||||
"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, {
|
const res = await fetch(url, options);
|
||||||
...options,
|
if (res.status === 500 && attempt < retries - 1) {
|
||||||
headers: {
|
continue; // retry on 500
|
||||||
...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.get(`${this.config.tubeApi}video?v=${v}`, {
|
curly
|
||||||
|
.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 vid = this.getJson(videoInfo);
|
const comments = await this.getJson(invComments);
|
||||||
|
|
||||||
|
const vid = await this.getJson(videoInfo);
|
||||||
const { json, video } = videoData;
|
const { json, video } = videoData;
|
||||||
|
|
||||||
let p = {};
|
var channel_uploads = { };
|
||||||
if (f === "true") {
|
if (f == "true") {
|
||||||
const uploads = await fetchWithRetry(`${this.config.invapi}/channels/${vid.authorId}?hl=${contentlang}®ion=${contentregion}`);
|
channel_uploads = await fetch(
|
||||||
p = this.getJson(await uploads.text());
|
`${this.config.invapi}/channels/${vid.authorId}?hl=${contentlang}®ion=${contentregion}`
|
||||||
|
);
|
||||||
|
var p = this.getJson(await channel_uploads.text());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!vid) {
|
if (!vid) {
|
||||||
console.log(`Sorry nya, we couldn't find any information about that video qwq`);
|
console.log(
|
||||||
|
`Sorry nya, we couldn't find any information about that video qwq`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.checkUnexistingObject(vid)) {
|
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,
|
||||||
@ -109,38 +151,59 @@ class InnerTubePokeVidious {
|
|||||||
engagement: fe.engagement,
|
engagement: fe.engagement,
|
||||||
wiki: "",
|
wiki: "",
|
||||||
desc: "",
|
desc: "",
|
||||||
color: await getColors(`https://i.ytimg.com/vi/${v}/hqdefault.jpg?sqp=${this.sqp}`).then(colors => colors[0].hex()),
|
color: await getColors(
|
||||||
color2: await getColors(`https://i.ytimg.com/vi/${v}/hqdefault.jpg?sqp=${this.sqp}`).then(colors => colors[1].hex()),
|
`https://i.ytimg.com/vi/${v}/hqdefault.jpg?sqp=${this.sqp}`
|
||||||
|
).then((colors) => colors[0].hex()),
|
||||||
|
color2: await getColors(
|
||||||
|
`https://i.ytimg.com/vi/${v}/hqdefault.jpg?sqp=${this.sqp}`
|
||||||
|
).then((colors) => colors[1].hex()),
|
||||||
},
|
},
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.cache[v].result;
|
return this.cache[v].result;
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.initError("Error getting video", error);
|
this.initError("Error getting video", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a video ID is valid.
|
||||||
|
* @param {string} v - Video ID.
|
||||||
|
* @returns {boolean} True if the video ID is valid, false otherwise.
|
||||||
|
*/
|
||||||
isvalidvideo(v) {
|
isvalidvideo(v) {
|
||||||
if (v != "assets" && v != "cdn-cgi" && v != "404") {
|
if (v != "assets" && v != "cdn-cgi" && v != "404") {
|
||||||
return /^([a-zA-Z0-9_-]{11})/.test(v);
|
const regex = new RegExp("^([a-zA-Z0-9_-]{11})");
|
||||||
}
|
const isMatch = regex.test(v);
|
||||||
|
return isMatch;
|
||||||
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize an error.
|
||||||
|
* @param {string} args - Error message.
|
||||||
|
* @param {Error} error - Error object.
|
||||||
|
*/
|
||||||
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