diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 00000000..4f0b5ae9 --- /dev/null +++ b/.drone.yml @@ -0,0 +1,19 @@ +kind: pipeline +type: exec +name: Build and Push Docker Image (Quay) + +platform: + os: linux + arch: amd64 + +steps: +- name: Build + environment: + QUAY_USERNAME: + from_secret: QUAY_USERNAME + QUAY_PASSWORD: + from_secret: QUAY_PASSWORD + commands: + - echo $QUAY_PASSWORD | docker login quay.io --username $QUAY_USERNAME --password-stdin + - docker build -t quay.io/sudovanilla/poketube . + - docker push quay.io/sudovanilla/poketube \ No newline at end of file diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 4b6e2785..b8974f0f 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,4 +1,4 @@ -# Contributor Covenant Code of Conduct +# Contributor Covenant Code of Conduct / PokeTube code of conduct ## Our Pledge @@ -60,15 +60,15 @@ representative at an online or offline event. Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at -iamashley@duck.com (E-mail) https://discord.gg/pfKSQ3pMfW (Discord server). +iamashley@duck.com (E-mail) https://discord.gg/pfKSQ3pMfW (Discord server) https://matrix.to/#/#poke:vern.cc (matrix space) and https://rvlt.gg/poke (revolt server). + All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the reporter of any incident. ## Additional Terms for Poketube - -**TL;DR**: You are not allowed to edit or remove these terms from Poketube. You can't remove this file from your Poketube fork. Everyone can copy and share this document as is, but making changes is not allowed. If your chosen alternative code of conduct doesn't include provisions against hate speech, inappropriate behavior, anti-immigrant sentiments, far-right or authoritarian content, it's not allowed. +**TL;DR**: You are encouraged not to edit or remove these terms from Poketube. While you have the freedom to make changes in your Poketube fork, if you choose to modify this document, please refrain from using the title "Poketube Code of Conduct." Everyone can copy and share this document as is, but making changes is allowed with the aforementioned condition. If your chosen alternative code of conduct doesn't include provisions against hate speech, inappropriate behavior, anti-immigrant sentiments, far-right, or authoritarian content, it's not recommended. 1. Definitions @@ -80,7 +80,7 @@ reporter of any incident. - **Inappropriate Behavior**: Inappropriate behavior encompasses actions or expressions that create an unwelcome, hostile, or offensive environment for others, such as harassment, intimidation, or bullying. -- **Authoritarianism**: Authoritarianism is characterized by an emphasis on strong central authority, limited individual freedoms, and restrictions on democratic processes. Content or behavior that promotes authoritarian principles, suppresses freedom of speech, individual rights, or democratic values is strictly prohibited. +- **Authoritarianism**: Authoritarianism is characterized by an emphasis on strong central authority, limited individual freedoms, and restrictions on democratic processes. Content or behavior that promotes authoritarian principles, suppresses freedom of speech, individual rights, or democratic values is strongly discouraged. - **Protected characteristics** include attributes such as race, ethnicity, gender, religion, sexual orientation, disability, and other traits or qualities safeguarded from discrimination by relevant laws and regulations. This defines what is meant by "protected characteristics" in the context of this document. @@ -88,26 +88,23 @@ reporter of any incident. NOTE: The Contributor Covenant Code of Conduct already includes provisions on some of these issues. Our intention is to provide a more defined and explicit statement regarding these prohibitions to ensure a clear and inclusive community environment. -YOU ARE ABSOLUTELY AND UNEQUIVOCALLY PROHIBITED FROM EDITING, REMOVING, OR ALTERING THE TERMS OF THIS FILE IN ANY WAY, SHAPE, OR FORM. FURTHERMORE, ONLY ASHLEY (THE AUTHOR) IS PERMITTED TO EDIT THIS CODE OF CONDUCT. YOU MAY NOT, UNDER ANY CIRCUMSTANCES, REMOVE THIS FILE FROM YOUR FORK OF POKETUBE. EVERY INDIVIDUAL, WITHOUT EXCEPTION, IS PERMITTED TO CREATE UNMODIFIED COPIES OF THIS DOCUMENT AND DISTRIBUTE IT AS IS; HOWEVER, THE MODIFICATION OF THIS DOCUMENT IS STRICTLY, UNMISTAKABLY, AND CATEGORICALLY FORBIDDEN. (The contact URLs within this code of conduct may be updated as needed to ensure accurate communication channels.) +YOU ARE NOT ENCOURAGED TO EDIT, REMOVE, OR ALTER THE TERMS OF THIS FILE. However, should you choose to make changes, please avoid using the title "Poketube Code of Conduct." Removing this file from your Poketube fork is allowed. Everyone, without exception, is permitted to create unmodified copies of this document and distribute it as is; however, modifications to this document are allowed with the aforementioned condition. + +It is of paramount importance to emphasize that the promotion or glorification of anti-immigrant sentiments, the alignment with far-right ideologies, Islamophobia, or any form of religious discrimination is strongly discouraged within the scope of Poketube. We maintain a stance against such content, which includes material that discriminates against immigrants, promotes hatred or hostility towards religious groups, or actively supports extremist beliefs associated with far-right ideologies. This stance is encouraged and non-binding. -If you do not wish to adhere to this conduct in your fork of Poketube, you have the option to utilize alternative codes of conduct instead. However, if you do not wish to adopt the alternative code of conduct, please feel free to contact us and explain your reasons for wanting to remove this file. +We believe in fostering an environment that is inclusive, respectful, and free from discrimination or the promotion of extremist ideologies. As such, any content found in violation of this encouragement will be addressed promptly and appropriately. -It is of paramount importance to emphasize that the promotion or glorification of anti-immigrant sentiments, the alignment with far-right ideologies, Islamophobia, or any form of religious discrimination is entirely and unequivocally prohibited within the scope of Poketube. We maintain a zero-tolerance stance on such content, which includes any material that discriminates against immigrants, promotes hatred or hostility towards religious groups, or actively supports extremist beliefs associated with far-right ideologies. This stance is unwavering and non-negotiable. - -We believe in fostering an environment that is inclusive, respectful, and free from discrimination or the promotion of extremist ideologies. As such, any content found in violation of this prohibition will be addressed promptly and appropriately. - -THE CLARITY AND FORCE OF THIS STATEMENT ARE INTENDED TO LEAVE NO ROOM FOR AMBIGUITY: ANTI-IMMIGRANT SENTIMENTS, FAR-RIGHT IDEOLOGIES, ISLAMOPHOBIA, RELIGIOUS DISCRIMINATION, MISOGYNY, AND SEXISM ARE STRICTLY OFF-LIMITS AND WILL NOT BE TOLERATED WITHIN OUR COMMUNITY. OUR COMMITMENT TO MAINTAINING A RESPECTFUL AND INCLUSIVE ATMOSPHERE EXTENDS TO ALL, REGARDLESS OF THEIR BACKGROUND, BELIEFS, OR IDENTITY. +THE CLARITY AND FORCE OF THIS STATEMENT ARE INTENDED TO ENCOURAGE CLEAR GUIDELINES: ANTI-IMMIGRANT SENTIMENTS, FAR-RIGHT IDEOLOGIES, ISLAMOPHOBIA, RELIGIOUS DISCRIMINATION, MISOGYNY, AND SEXISM ARE STRONGLY DISCOURAGED AND NOT PREFERRED WITHIN OUR COMMUNITY. OUR HOPE IS TO MAINTAIN A RESPECTFUL AND INCLUSIVE ATMOSPHERE FOR ALL, REGARDLESS OF THEIR BACKGROUND, BELIEFS, OR IDENTITY. These terms may be subject to change, and any updates will be communicated to the Poketube community. Changes to these terms will be communicated to users. **3. Application of GNU Kind Communication Policy** -These terms also apply the principles outlined in the [GNU Kind Communication Policy](https://www.gnu.org/philosophy/kind-communication.html), which encourage respectful and inclusive communication within the Poketube community. +These terms also align with the principles outlined in the [GNU Kind Communication Policy](https://www.gnu.org/philosophy/kind-communication.html), which encourage respectful and inclusive communication within the Poketube community. It is crucial to note that we respect the diverse opinions and beliefs of our users. -***Additional terms end lol*** - +***Additional terms end lol*** ## Enforcement Guidelines diff --git a/Dockerfile b/Dockerfile index c934dca0..66f2062b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,7 +25,7 @@ RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg - RUN echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_18.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list RUN apt-get update -RUN apt-get -y install nodejs +RUN apt-get -y install nodejs npm # Install Packages RUN npm install diff --git a/README.md b/README.md index b66a45f5..a32d4b31 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,28 @@ +# see https://codeberg.org/Ashley/poke/issues/59 if you are having problems using poke +

+ +

The Ultimate Privacy App

+
- Be Anonymous watching epic videos, searching thingys on the interwebs and listening to music on poke - the free privacy front end!
+ Be Anonymous watching epic videos, searching thingys on the interwebs and listening to music on poke - the free privacy front end! + + "Since you work on poke, Are you in touch with its lead developer "Jose marchasi"?
+-RMS + +Stallman though poke was GNU poke lmaoooo +
+ + +
[Welcome!](#welcome)   |   [Features](#features)   |   [No non-free codec needed](#no-non-free-codec-needed-3)   |   [Hosting Poke~](#hosting-poketube)   |   [Poke community!](#poketube-community)   |   [The Legal Stuff (boring tbh)](#the-legal-stuff-boring-tbh) @@ -27,7 +43,7 @@ ## Welcome! -This is the source code of PokeTube, the privacy-friendly youtube front-end built with the InnerTube API! +This is the source code of Poke (formerly PokeTube), the privacy-friendly youtube front-end built with the InnerTube API!

Features

@@ -129,11 +145,16 @@ The port can be changed with the config file you downloaded, just change the `se see [here](https://codeberg.org/Ashley/poke/src/branch/main/january) :3 just uhh change the url in config.json to ur image proxy -## PokeTube community! +## Poke community! -Join the community on [revolt](https://rvlt.gg/poketube) :3 +Join the community on [revolt](https://rvlt.gg/poketube) or [matrix](https://matrix.to/#/#poke:vern.cc) :3 ## The Legal Stuff (boring tbh) +the main parts of the project is Under GPL-3.0-OR-LATER :3 + +see the each sections LICENSE tho!! +Copyleft 2021-202x Poke Project + [Code Of conduct](https://codeberg.org/Ashley/poketube/src/branch/main/CODE_OF_CONDUCT.md) diff --git a/config.json b/config.json index f733bdb1..987b259e 100644 --- a/config.json +++ b/config.json @@ -3,6 +3,7 @@ "invapi": "https://invid-api.poketube.fun/api/v1", "dislikes": "https://returnyoutubedislikeapi.com/votes?videoId=", "invchannel": "https://invid-api.poketube.fun/api/v1", + "p_url":"https://p.poketube.fun", "media_proxy": "https://image-proxy.poketube.fun", "cacher_max_age": "864000", "enablealwayshttps": false, diff --git a/css/app.js b/css/app.js index a9c47dfb..bf53ec15 100644 --- a/css/app.js +++ b/css/app.js @@ -98,7 +98,7 @@ function fadeInElements() { window.addEventListener('scroll', fadeInElements); document.addEventListener('fullscreenchange', fadeInElements); -setInterval(fadeInElements, 500); +setInterval(fadeInElements, 100); function jumpToTime(e) { e.preventDefault(); @@ -202,30 +202,100 @@ function fetchUrls(urls) { }); } -/* -// Fetch channel URLs -const channelUrls = document.querySelectorAll('a[href*="/channel?id="]'); -fetchUrls(channelUrls); + function anondocumenttitle(message, times) { + var hash = CryptoJS.SHA256(message); -// Fetch download URLs -const downloadUrls = document.querySelectorAll('a[href*="/download?v="]'); -fetchUrls(downloadUrls); + return hash.toString(CryptoJS.enc.Hex); + } + + if(navigator.globalPrivacyControl) { + var gpcValue = navigator?.globalPrivacyControl + } else { + var gpcValue = false + } + + if (location.hostname === "poketube.fun") { + if (typeof Ashley === "undefined") { + var Ashley = {}; + } + Ashley.dntEnabled = function (dnt, ua) { + "use strict"; + var dntStatus = + dnt || + navigator.doNotTrack || + window.doNotTrack || + navigator.msDoNotTrack; + var userAgent = ua || navigator.userAgent; + var anomalousWinVersions = [ + "Windows NT 6.1", + "Windows NT 6.2", + "Windows NT 6.3", + ]; + var fxMatch = userAgent.match(/Firefox\/(\d+)/); + var ieRegEx = /MSIE|Trident/i; + var isIE = ieRegEx.test(userAgent); + var platform = userAgent.match(/Windows.+?(?=;)/g); + if (isIE && typeof Array.prototype.indexOf !== "function") { + return false; + } else if (fxMatch && parseInt(fxMatch[1], 10) < 32) { + dntStatus = "Unspecified"; + } else if ( + isIE && + platform && + anomalousWinVersions.indexOf(platform.toString()) !== -1 + ) { + dntStatus = "Unspecified"; + } else { + dntStatus = { 0: "Disabled", 1: "Enabled" }[dntStatus] || "Unspecified"; + } + return dntStatus === "Enabled" ? true : false; + }; + // only load if DNT is not enabled + if(!gpcValue) { + if (Ashley && !Ashley.dntEnabled()) { + var _paq = (window._paq = window._paq || []); + /* tracker methods like "setCustomDimension" should be called before "trackPageView" */ + _paq.push([ + "setDocumentTitle", + anondocumenttitle(document.domain, 5) + + "/" + + anondocumenttitle(document.title, 5), + ]); + _paq.push(["setDoNotTrack", true]); + _paq.push(["disableCookies"]); + _paq.push(["trackPageView"]); + _paq.push(["enableLinkTracking"]); + (function () { + var u = "//data.poketube.fun/"; + _paq.push(["setTrackerUrl", u + "matomo.php"]); + _paq.push(["setSiteId", "2"]); + var d = document, + g = d.createElement("script"), + s = d.getElementsByTagName("script")[0]; + g.async = true; + g.src = u + "matomo.js"; + s.parentNode.insertBefore(g, s); + })(); + } + } + } -// fetch videos urls -const urls = document.querySelectorAll('a[href*="/watch?v="]'); -fetchUrls(urls); -*/ var popupMenu = document.getElementById("popupMenu"); var loopOption = document.getElementById("loopOption"); var speedOption = document.getElementById("speedOption"); + - video.addEventListener("contextmenu", function(event) { - event.preventDefault(); +video.addEventListener("contextmenu", function(event) { + // Check if the video is in fullscreen mode + if (!document.fullscreenElement && !document.webkitFullscreenElement && !document.mozFullScreenElement && !document.msFullscreenElement) { + event.preventDefault(); + + popupMenu.style.display = "block"; + popupMenu.style.left = event.pageX + "px"; + popupMenu.style.top = event.pageY + "px"; + } +}); - popupMenu.style.display = "block"; - popupMenu.style.left = event.pageX + "px"; - popupMenu.style.top = event.pageY + "px"; - }); // Hide the popup menu when clicking outside of it window.addEventListener("click", function(event) { @@ -233,14 +303,33 @@ fetchUrls(urls); popupMenu.style.display = "none"; } }); - + + var loopedIndicator = document.getElementById("loopedIndicator"); + + loopedIndicator.style.display = "none"; // Initially hide the indicator + loopOption.addEventListener("click", function() { - video.loop = !video.loop; - if (video.loop) { - alert("Looped!"); + var looped = video.loop; + video.loop = !looped; + + + // Update the looped indicator popup + var displaySpecialText = Math.random() < 0.5; + + // Update the looped indicator popup + if (displaySpecialText) { + var specialText = looped ? "Unlooped >.<" : "Looped~ :3 >~<"; + loopedIndicator.textContent = specialText; } else { - alert("unlooped!") + loopedIndicator.textContent = looped ? "Unlooped!" : "Looped!"; } + loopedIndicator.style.display = "block"; + + // Hide the indicator after 2 seconds + setTimeout(function() { + loopedIndicator.style.display = "none"; + }, 2000); + }); speedOption.addEventListener("click", function() { @@ -263,4 +352,6 @@ fetchUrls(urls); return 2; } } + +const GoogleTranslateEndpoint = "https://translate.google.com/_/TranslateWebserverUi/data/batchexecute?rpcids=MkEWBc&rt=c" // @license-end \ No newline at end of file diff --git a/css/app.main.css b/css/app.main.css index 76c7eb49..3960372f 100644 --- a/css/app.main.css +++ b/css/app.main.css @@ -1258,15 +1258,6 @@ nav .right img { border-radius: 50%; } -@font-face { - font-family: "PokeTube Flex"; - src: url("https://p.poketube.fun/https://cdn.glitch.global/43b6691a-c8db-41d4-921c-8cf6aa0d9108/robotoflex.ttf?v=1668343428681"); - font-style: normal; - font-stretch: 1% 800%; - font-weight: 1 1000; - font-display: swap; -} - .video > .thumbnail > .video-length { font-size: smaller; background-color: #0008; diff --git a/css/favicon.ico b/css/favicon.ico new file mode 100644 index 00000000..48608434 Binary files /dev/null and b/css/favicon.ico differ diff --git a/css/poke-chan-outfit-a.png b/css/poke-chan-outfit-a.png new file mode 100644 index 00000000..1ef4eecc Binary files /dev/null and b/css/poke-chan-outfit-a.png differ diff --git a/css/poke-screnshot-a.png b/css/poke-screnshot-a.png new file mode 100644 index 00000000..dc773f22 Binary files /dev/null and b/css/poke-screnshot-a.png differ diff --git a/css/poketube.css b/css/poketube.css index fd6b7e64..ef0fc5d7 100644 --- a/css/poketube.css +++ b/css/poketube.css @@ -19,6 +19,58 @@ */ +/* latin */ +@font-face { + font-family: 'Montserrat'; + font-style: normal; + font-weight: 500; + font-stretch: 100%; + src: url(https://p.poketube.fun/https://fonts.bunny.net/montserrat/files/montserrat-latin-500-normal.woff2) format('woff2'), url(https://p.poketube.fun/https://fonts.bunny.net/montserrat/files/montserrat-latin-500-normal.woff) format('woff'); + unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; +} + +/* cyrillic */ +@font-face { + font-family: 'Montserrat'; + font-style: normal; + font-weight: 500; + font-stretch: 100%; + src: url(https://p.poketube.fun/https://fonts.bunny.net/montserrat/files/montserrat-cyrillic-500-normal.woff2) format('woff2'), url(https://p.poketube.fun/https://fonts.bunny.net/montserrat/files/montserrat-cyrillic-500-normal.woff) format('woff'); + unicode-range: U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116; +} + +/* latin-ext */ +@font-face { + font-family: 'Montserrat'; + font-style: normal; + font-weight: 500; + font-stretch: 100%; + src: url(https://p.poketube.fun/https://fonts.bunny.net/montserrat/files/montserrat-latin-ext-500-normal.woff2) format('woff2'), url(https://p.poketube.fun/https://fonts.bunny.net/montserrat/files/montserrat-latin-ext-500-normal.woff) format('woff'); + unicode-range: U+0100-02AF,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF; +} + +/* vietnamese */ +@font-face { + font-family: 'Montserrat'; + font-style: normal; + font-weight: 500; + font-stretch: 100%; + src: url(https://p.poketube.fun/https://fonts.bunny.net/montserrat/files/montserrat-vietnamese-500-normal.woff2) format('woff2'), url(https://p.poketube.fun/https://fonts.bunny.net/montserrat/files/montserrat-vietnamese-500-normal.woff) format('woff'); + unicode-range: U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB; +} + +/* cyrillic-ext */ +@font-face { + font-family: 'Montserrat'; + font-style: normal; + font-weight: 500; + font-stretch: 100%; + src: url(https://p.poketube.fun/https://fonts.bunny.net/montserrat/files/montserrat-cyrillic-ext-500-normal.woff2) format('woff2'), url(https://p.poketube.fun/https://fonts.bunny.net/montserrat/files/montserrat-cyrillic-ext-500-normal.woff) format('woff'); + unicode-range: U+0460-052F,U+1C80-1C88,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F; +} + + + :root { /* text */ --text-link: #0ab7f0; @@ -198,24 +250,31 @@ a.avatar { } .recommended-list { - background-color: var(--div-prim-bg); - border-radius: 1.5em; + background-color: var(--div-prim-bg); + border-radius: 1.5em; + /* padding-right: 24px; */ margin: 10px; - margin-top: 0px; - margin-left: 0px; - height: -moz-fit-content; - height: fit-content; - justify-self: center; - margin-right: -0.9em; - /* width: min-content;*/ - border: var(--div-border-color); - border-style: solid; - max-width: 371px; - width: max-content; + margin-top: 0; + margin-left: 0; + height: -moz-fit-content; + height: fit-content; + /* justify-self: center; */ + margin-right: -.9em; + border: var(--div-border-color); + border-style: solid; + max-width: 371px; + width: 20.9em; } .video-views { - white-space: nowrap; + white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: pre-wrap; /* css-3 */ + word-wrap: break-word; /* Internet Explorer 5.5+ */ + white-space: -webkit-pre-wrap; /* Newer versions of Chrome/Safari*/ + word-break: break-all; + white-space: normal; } .video-info-panel.gradient { @@ -234,7 +293,6 @@ a.avatar { font-weight: 1000; font-stretch: ultra-expanded; overflow: hidden; - text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 3; line-clamp: 3; @@ -402,7 +460,7 @@ a.avatar { border-radius: 4px; word-break: break-all; white-space: nowrap; - font-family: ubuntu, sans-serif; + font-family: "Montserrat", sans-serif; } .new-button { @@ -513,7 +571,7 @@ a.avatar { margin: 0; width: 300px; border-radius: 8px; - font-family: ubuntu, sans-serif; + font-family: "Montserrat", sans-serif; box-shadow: var(--border-color) 0 0 5px; background-color: var(--context-menu-background); } @@ -523,10 +581,12 @@ a.avatar { flex-direction: row; align-items: center; padding: 0 16px; + padding-left: 16px; height: 40px; column-gap: 16px; color: var(--text-primary); text-decoration: none; + font-weight: 500; } .dropdown__item:hover { @@ -679,7 +739,7 @@ a.new-button:hover { border-radius: 10px; height: fit-content; padding: 10px; - font-family: ubuntu, sans-serif; + font-family: "ubuntu", sans-serif; margin-left: -11em; width: 43em; position: absolute; @@ -779,7 +839,6 @@ object-fit:none; font-stretch: expanded; overflow:hidden; font-family: var(--text-font-primary); - margin-left: auto; margin-right: auto; width: auto; max-width: 21em; @@ -794,7 +853,9 @@ object-fit:none; } .video > .info { -font-family: Ubuntu, sans-serif; +font-family: "Montserrat", sans-serif; +font-weight: 500; + } /* Width */ diff --git a/html/account-me.ejs b/html/account-me.ejs index 4528f476..01c57b21 100644 --- a/html/account-me.ejs +++ b/html/account-me.ejs @@ -93,9 +93,4 @@ a {
- - \ No newline at end of file + \ No newline at end of file diff --git a/html/apps.ejs b/html/apps.ejs new file mode 100644 index 00000000..2fdf74af --- /dev/null +++ b/html/apps.ejs @@ -0,0 +1,135 @@ + + + + + + + Poke Apps + + + + + + + + + + +
+
+

Moar from Poke

+

Poke is not just a youtube front end - its moar!!

+
+ + Games + Web Search + Translate + Maps + PokeTube + Settings +
+ + diff --git a/html/channel.ejs b/html/channel.ejs index f2869bd6..4b39c086 100644 --- a/html/channel.ejs +++ b/html/channel.ejs @@ -1,9 +1,9 @@ -<% try { %> + <% try { %> + + <% if (ID === "UCFAiFyGs6oDiF1Nf-rRJpZA") { %> Technoblade Never Dies! - PokeTube <% } %> <%=j.Channel?.Metadata.Name%> - PokeTube - + + - - - - <% if (j.Channel?.Metadata.Banners.Thumbnail) { %> - + + <% if (j.Channel?.Metadata.Banners.Thumbnail) { %> <% } %> - - - + <% if(!isMobile) { %> + + + <% } %> -
+

<%=j.Channel?.Metadata.Name%> - - <% if (cinv?.authorVerified) { %> - <% if (cinv?.isFamilyFriendly) { %> + <% if (cinv?.authorVerified) { %> - + + + + <% } %> - <% if (!cinv.isFamilyFriendly) { %> - - - <% } %> - - <% } %> - <% if (cinv?.isFamilyFriendly) { %> - - - <% } %> - -

-

<%=subs%> subscribers

+ @<%- cinv.authorId %>@youtube.com +

+

<%=subs%> subscribers

<% try { %> - <%- getFirstLine(cinv.description).slice(0, 60) %> - + <%- getFirstLine(cinv.description).slice(0, 60) || "More from this channel (soon)"%> + <% } catch (error) { %>

Error: <%= error.message %>

<% } %> -
@@ -652,8 +731,62 @@ white-space: nowrap;text-decoration: none;" href="/feeds/videos.xml?channel_id=< <% } %> <% } %> +<% if (Array.isArray(playlist?.playlists)) { %> + + <% if (playlist.playlists.length != "0") { %> + + Playlists + <% } %> + <% } %> + <% } %> + +<% if (tab === "playlist") { %> + + Videos + +<% if (Array.isArray(shorts?.videos)) { %> + <% if (shorts.videos[0]) { %> +<% if (turntomins(shorts.videos[0].lengthSeconds) != "aN:aN" ) { %> + + + Shorts + <% } %> + <% } %> + + <% } %> + + <% if (Array.isArray(stream?.videos)) { %> + <% if (stream.videos[0]) { %> + +<% if (turntomins(stream.videos[0].lengthSeconds) != "aN:aN" ) { %> + + Live + <% } %> + <% } %> + + <% } %> + + <% if (Array.isArray(c?.comments)) { %> + + <% if (c.comments.length != "0") { %> + + Community + <% } %> + <% } %> + +<% if (Array.isArray(playlist?.playlists)) { %> + + <% if (playlist.playlists.length != "0") { %> + + Playlists + <% } %> + <% } %> + + + <% } %> + <% if (tab === "about") { %> Videos @@ -711,6 +844,15 @@ white-space: nowrap;text-decoration: none;" href="/feeds/videos.xml?channel_id=< Community + +<% if (Array.isArray(playlist?.playlists)) { %> + + <% if (playlist.playlists.length != "0") { %> + + Playlists + <% } %> + <% } %> + <% } %> <% if (tab === "shorts") { %> @@ -738,9 +880,18 @@ white-space: nowrap;text-decoration: none;" href="/feeds/videos.xml?channel_id=< <% } %> <% } %> + +<% if (Array.isArray(playlist?.playlists)) { %> + + <% if (playlist.playlists.length != "0") { %> + + Playlists + <% } %> + <% } %> + <% } %> - <% if (tab === "live") { %> + <% if (tab === "live") { %> Videos <% if (Array?.isArray(shorts?.videos)) { %> @@ -765,6 +916,7 @@ white-space: nowrap;text-decoration: none;" href="/feeds/videos.xml?channel_id=< <% } %> <% } %> +
@@ -1110,7 +1262,7 @@ width: fit-content; <% if (Array?.isArray( shorts.videos)) { %> <% shorts.videos.forEach (x => { %> - + <%- x.title %> <% }) %> @@ -1122,8 +1274,17 @@ width: fit-content; Next Page <% } %> + + + + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + <% } %> @@ -1237,7 +1389,41 @@ width: fit-content; <% } %> + <% if (tab === "playlist") { %> + + + +
+ + +
+ + <% if (Array.isArray(playlist.playlists)) { %> + + <% playlist.playlists.forEach (x => { %> + +
<%- x.videoCount %> Videos
+
+ <%- x.title %> + +
+
+ <% }) %> + <% } %> + + + + + + +
+ + + + <% } %> + + <% if (tab === "community") { %> <% if (Array?.isArray( c?.comments)) { %>
@@ -1320,39 +1506,38 @@ width: fit-content; <% if (tab === "about") { %> -
-

About

+ + <% if (!isMobile) { %> + + +
+ + +
+

About

<% if (cinv.descriptionHtml) { %>

<%-cinv.descriptionHtml%>

<% } %> - <% if (wiki.extract_html) { %> -

From the web

+
+ + <% } %> + + <% if (isMobile) { %> + -
-

- <%-wiki.extract_html%>

- -
-
+
+

About

-

+ <% if (cinv.descriptionHtml) { %> - From wikipedia under CC-BY-SA 3.0 -

-
- - -

- <% } %> -
- YouTube removed the about tab ;_; fix for this soon lol -
+

<%-cinv.descriptionHtml%>

+ <% } %> + <% } %>
<% } %> @@ -1370,8 +1555,8 @@ if (userID) { anchor.href = `/api/set-channel-subs?ID=${userID}&channelName=<%=j.Channel?.Metadata.Name%>&avatar=https://p.poketube.fun/<%- j.Channel?.Metadata.Avatars.Thumbnail?.$t %>&channelID=<%= ID %>`; } else { // If user ID doesn't exist in localStorage, you can handle it as needed - console.log("User ID not found in localStorage"); - // Optionally, you can set a default href or display an error message. + anchor.href = "/account-create" + // Optionally, you can set a default href or display an error message. } document.getElementById('search').addEventListener('keyup', function () { @@ -1405,7 +1590,28 @@ document.getElementById('search').addEventListener('keyup', function () { } }); }); - + var isPopupOpen = false; + + function togglePopup() { + if (isPopupOpen) { + closePopup(); + } else { + document.getElementById('popup-container').style.display = 'block'; + document.body.style.overflow = 'hidden'; + } + isPopupOpen = !isPopupOpen; + } + + function closePopup() { + document.getElementById('popup-container').style.display = 'none'; + document.body.style.overflow = 'auto'; + isPopupOpen = false; + } + + document.getElementById('popup-trigger').addEventListener('click', function (event) { + event.preventDefault(); + togglePopup(); + }); // @license-end @@ -1417,8 +1623,4 @@ document.getElementById('search').addEventListener('keyup', function () { <% } catch (error) { %> <% } %> - \ No newline at end of file + \ No newline at end of file diff --git a/html/discover.ejs b/html/discover.ejs index 2a6b330b..70332e30 100644 --- a/html/discover.ejs +++ b/html/discover.ejs @@ -1,7 +1,7 @@ - - + <% } %> - + <% } %> diff --git a/html/gamehub.ejs b/html/gamehub.ejs new file mode 100644 index 00000000..eca8b8b8 --- /dev/null +++ b/html/gamehub.ejs @@ -0,0 +1,1111 @@ + +<% if (!game) { %> + + + + + + + + + + + + + + Gaming Hub + + + + + + <% } %> +<% if (game === "snake") { %> + + + + + + + + Snak + + + + + + + + + <% } %> +<% if (game === "tic-tac-toe") { %> + + + + + + + + Tic-Tac-Toe + + +
+

Tic-Tac-Toe

+
+
+
+ + + + + + + <% } %> +<% if (game === "pong") { %> + + + + + + + + Pong + + + +
+

+ U can press space to start owo +

+

Left Paddle Controls : W (Up) and S (Down)

+

Right Paddle Controls: Arrow Up (Up) and Arrow Down (Down)

+
+ + + + + + + <% } %> +<% if (game === "sudoku") { %> + + + + + + + + Sudoku + + +
+
+ + + + + + + <% } %> + \ No newline at end of file diff --git a/html/landing.ejs b/html/landing.ejs index 164341da..eb54af6c 100644 --- a/html/landing.ejs +++ b/html/landing.ejs @@ -1,7 +1,8 @@ @@ -74,18 +76,18 @@ body { -
-
+ @@ -99,18 +101,34 @@ body {

No Tracking & Ads

Very Fast

-

Built-in video downloder

+

Built-in video downloader

Web Search

- - - + + + + + +
- - \ No newline at end of file + \ No newline at end of file diff --git a/html/lite.ejs b/html/lite.ejs index 2c904271..3b81ed22 100644 --- a/html/lite.ejs +++ b/html/lite.ejs @@ -3,7 +3,7 @@ This Source Code Form is subject to the terms of the GNU General Public License: - Copyright (C) 2021-2023 POKETUBE (https://codeberg.org/Ashley/poketube) + Copyright (C) 2021-2024 POKETUBE (https://codeberg.org/Ashley/poketube) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -557,34 +557,70 @@ background: none !important;
<% if (!f) { %> - <% k.Video.Recommendations.Video.forEach(x => { %> -
- <% if (!optout) { %> + +<% if (inv_vid.recommendedVideos) { %> - <%=x.duration || "LIVE" %> - <% } %> - <% if (optout) { %> - - <%- x.duration || "LIVE"%> - <% } %> - -
- - <% if (!optout) { %> - <%= x.Title %> - <% } %> - <% if (optout) { %> - <%= x.Title %> - <% } %> -
- <%=x.Channel.Name %> -
<%= x.uploadedAt.replace("Streamed", "Live") %> • <%= convert(x.views) %> views
-
-
-
- - <% }) %> +<% inv_vid?.recommendedVideos.forEach(x => { %> +
+ <% if (!optout) { %><%- turntomins(x.lengthSeconds) || "LIVE"%><% } %><% if (optout) { %><%- x.duration || "LIVE"%><% } %> +
+ <% if (!optout) { %> + + <%= x.title %> + + <% } %> + <% if (optout) { %> + + <%= x.title %> + <% } %> +
+ + <%=x.author %> + +
+ + <%= convert(x.viewCount) %> views + +
+
+
+
+ <% }) %> + + + <% } %> + <% } %> + + <% if (inv_vid.recommendedVideos.length < 1) { %> + <% channel_uploads.latestVideos.forEach(x => { %> +
+ <% if (!optout) { %><%- turntomins(x.lengthSeconds) || "LIVE"%><% } %><% if (optout) { %><%- x.duration || "LIVE"%><% } %> +
+ <% if (!optout) { %> + + <%= x.title %> + + <% } %> + <% if (optout) { %> + + <%= x.title %> + + <% } %> +
+ + <%=x.author %> + +
+ + <%= convert(x.viewCount) %> views + +
+
+
+
+ <% }) %> + <% } %> <% } %> diff --git a/html/playlist.ejs b/html/playlist.ejs new file mode 100644 index 00000000..9bbd4816 --- /dev/null +++ b/html/playlist.ejs @@ -0,0 +1,265 @@ + + + Poke | <%- p.title %> + + + + + + + + + + + + + + + + + + + + +
+
+ <% if (!p.mixId) { %> + +
+
<% } %> + +

<%- p.title %>

+ <% if (!p.mixId) { %> + <%- p.videoCount %> videos • <%- p?.viewCount?.toLocaleString() %> views • by <%- p.author %> + <% } %> + + <%- p.description %> +
+ +
+
+
+ <% p.videos.forEach(x => { %> + + + + <% }) %> + + +
+ + +
+
+ + + + + diff --git a/html/poketube.ejs b/html/poketube.ejs index 48f366d5..edd06561 100644 --- a/html/poketube.ejs +++ b/html/poketube.ejs @@ -12,7 +12,7 @@ This Source Code Form is subject to the terms of the GNU General Public License: - Copyright (C) 2021-2023 POKETUBE (https://codeberg.org/Ashley/poketube) + Copyright (C) 2021-2024 POKETUBE (https://codeberg.org/Ashley/poketube) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -29,33 +29,33 @@ --> - - +<% if(secure) { %><% } %><% if(!secure) { %><% } %> + + + + <% if (e === false) { %> - + <% } %> <% if (!e) { %> - - + - - <% } %> + <% } %> + + - <%=inv_vid.title%> | PokeTube - + <% } %> - - + +
- + \ No newline at end of file diff --git a/html/search-web.ejs b/html/search-web.ejs index 5177c905..c352c341 100644 --- a/html/search-web.ejs +++ b/html/search-web.ejs @@ -1,7 +1,7 @@ <% if (q == "do the harlem shake") { %> @@ -99,8 +99,20 @@ summary:hover{ white-space: nowrap; font-family: ubuntu, sans-serif; } - +.container { + max-width: 800px; + margin: 0 auto; + padding: 20px; + background-color: #333; + border: 1px solid #ccc; + border-radius: 5px; + text-align:center; + } + .container > * { + text-align:center !important; + + } .info > div { font-family:Ubuntu, sans-serif; } @@ -276,6 +288,16 @@ border:solid; transform: scale(1, 1); } +.something-background-a { + background-image: url('<%- media_proxy_url %>/proxy?url=https://static.wikia.nocookie.net/omori/images/f/fc/Something_Bed_(2018_Demo).gif') !important; +} +.something-background-b { + background-image: url('<%- media_proxy_url %>/proxy?url=https://static.wikia.nocookie.net/omori/images/1/14/Hangman_%28Laptop%29.png') !important; +} +.something-background-c { + background-image: url('<%- media_proxy_url %>/proxy?url=https://static.wikia.nocookie.net/omori/images/6/67/Nanci_Before.png') !important; +} + .loading .spinner { display: inline-block; border: 5px solid rgba(255, 255, 255, 0.2); @@ -332,11 +354,22 @@ video[counter].classList.add("shake"); <% } %> - <% if (q != "do the harlem shake") { %> - - <% if (q != "want you gone") { %> <% if (q != "portal 2 ending") { %> <% if (q != "credits") { %> <% if (q != "glados") { %> + <% if (q == "do a barrel roll") { %> + + + <% } %> + + <% if (q != "do the harlem shake") { %> <% if (q != "want you gone") { %> <% if (q != "portal 2 ending") { %> <% if (q != "credits") { %> <% if (q != "glados") { %> <% if (q != "something") { %> @@ -344,8 +377,8 @@ video[counter].classList.add("shake"); <% } %> - <% } %> - <% } %> + <% } %><% } %> + <% } %> <% } %> @@ -376,7 +409,6 @@ video[counter].classList.add("shake"); - @@ -467,6 +499,23 @@ Web + + <% if (q.includes("suicide")) { %> + +
+

You are not alone

+

+ if you or somebody you know is having a bad time, talk to somebody today. +

+

+ if you are from the US, call 988. if you arent see this url. +

dont worry, ur not alone <3 and you are really important btw! +

+ +
+ <% } %> + <% if (!tab) { %> @@ -509,7 +558,7 @@ font-weight: 1000;
- <% if (continuation !== "1") { %> + <% if (Number(continuation) >= "2") { %>

First Page

@@ -518,7 +567,7 @@ font-weight: 1000;

<% } %> - <% if (continuation == "1" || !continuation) { %> + <% if (Number(continuation) <= "0" || !continuation) { %>

Next Page @@ -575,11 +624,70 @@ font-weight: 1000;

- + + - \ No newline at end of file + \ No newline at end of file diff --git a/html/translate.ejs b/html/translate.ejs new file mode 100644 index 00000000..b6200b0d --- /dev/null +++ b/html/translate.ejs @@ -0,0 +1,431 @@ + + + + + + PokeTranslate + + + + + + + + + + + + + + <% if (isMobile) { %> + + <% } %> + + <% if (!isMobile) { %> + + <% } %> + + + +
+ +

PokeTranslate

+ +
+ + +
+
+ + <% const languageOptions = [ + { code: 'autodetect', name: 'Autodetect' }, + { code: 'af', name: 'Afrikaans' }, + { code: 'sq', name: 'Albanian' }, + { code: 'am', name: 'Amharic' }, + { code: 'ar', name: 'Arabic' }, + { code: 'hy', name: 'Armenian' }, + { code: 'as', name: 'Assamese' }, + { code: 'ay', name: 'Aymara' }, + { code: 'az', name: 'Azerbaijani' }, + { code: 'bm', name: 'Bambara' }, + { code: 'eu', name: 'Basque' }, + { code: 'be', name: 'Belarusian' }, + { code: 'bn', name: 'Bengali' }, + { code: 'bh', name: 'Bhojpuri' }, + { code: 'bs', name: 'Bosnian' }, + { code: 'bg', name: 'Bulgarian' }, + { code: 'ca', name: 'Catalan' }, + { code: 'ceb', name: 'Cebuano' }, + { code: 'ny', name: 'Chichewa' }, + { code: 'zh-cn', name: 'Chinese (Simplified)' }, + { code: 'zh-tw', name: 'Chinese (Traditional)' }, + { code: 'co', name: 'Corsican' }, + { code: 'hr', name: 'Croatian' }, + { code: 'cs', name: 'Czech' }, + { code: 'da', name: 'Danish' }, + { code: 'dv', name: 'Dhivehi' }, + { code: 'doi', name: 'Dogri' }, + { code: 'nl', name: 'Dutch' }, + { code: 'en', name: 'English' }, + { code: 'eo', name: 'Esperanto' }, + { code: 'et', name: 'Estonian' }, + { code: 'ee', name: 'Ewe' }, + { code: 'tl', name: 'Filipino' }, + { code: 'fi', name: 'Finnish' }, + { code: 'fr', name: 'French' }, + { code: 'fy', name: 'Frisian' }, + { code: 'gl', name: 'Galician' }, + { code: 'ka', name: 'Georgian' }, + { code: 'de', name: 'German' }, + { code: 'el', name: 'Greek' }, + { code: 'gn', name: 'Guarani' }, + { code: 'gu', name: 'Gujarati' }, + { code: 'ht', name: 'Haitian Creole' }, + { code: 'ha', name: 'Hausa' }, + { code: 'haw', name: 'Hawaiian' }, + { code: 'he', name: 'Hebrew' }, + { code: 'hi', name: 'Hindi' }, + { code: 'hmn', name: 'Hmong' }, + { code: 'hu', name: 'Hungarian' }, + { code: 'is', name: 'Icelandic' }, + { code: 'ig', name: 'Igbo' }, + { code: 'ilo', name: 'Ilocano' }, + { code: 'id', name: 'Indonesian' }, + { code: 'ga', name: 'Irish' }, + { code: 'it', name: 'Italian' }, + { code: 'ja', name: 'Japanese' }, + { code: 'jv', name: 'Javanese' }, + { code: 'kn', name: 'Kannada' }, + { code: 'kk', name: 'Kazakh' }, + { code: 'km', name: 'Khmer' }, + { code: 'rw', name: 'Kinyarwanda' }, + { code: 'kok', name: 'Konkani' }, + { code: 'ko', name: 'Korean' }, + { code: 'kri', name: 'Krio' }, + { code: 'ku', name: 'Kurdish (Kurmanji)' }, + { code: 'sd', name: 'Sindhi' }, + { code: 'si', name: 'Sinhala' }, + { code: 'sk', name: 'Slovak' }, + { code: 'sl', name: 'Slovenian' }, + { code: 'so', name: 'Somali' }, + { code: 'es', name: 'Spanish' }, + { code: 'su', name: 'Sundanese' }, + { code: 'sw', name: 'Swahili' }, + { code: 'sv', name: 'Swedish' }, + { code: 'tg', name: 'Tajik' }, + { code: 'ta', name: 'Tamil' }, + { code: 'tt', name: 'Tatar' }, + { code: 'te', name: 'Telugu' }, + { code: 'th', name: 'Thai' }, + { code: 'ti', name: 'Tigrinya' }, + { code: 'ts', name: 'Tsonga' }, + { code: 'tr', name: 'Turkish' }, + { code: 'tk', name: 'Turkmen' }, + { code: 'twi', name: 'Twi' }, + { code: 'uk', name: 'Ukrainian' }, + { code: 'ur', name: 'Urdu' }, + { code: 'ug', name: 'Uyghur' }, + { code: 'uz', name: 'Uzbek' }, + { code: 'vi', name: 'Vietnamese' }, + { code: 'cy', name: 'Welsh' }, + { code: 'xh', name: 'Xhosa' }, + { code: 'yi', name: 'Yiddish' }, + { code: 'yo', name: 'Yoruba' }, + { code: 'zu', name: 'Zulu' } +]; %> + + + + + + + + + + +
+
+ + + + +
+
+ +
+ + + +
+ +
+
+ +
+ +
+ + +
+ +
+ + + +
+ + + + +
+ + + + + +
+
+
+ + + + + + + \ No newline at end of file diff --git a/instances.json b/instances.json index a3e23283..ac85f7f2 100644 --- a/instances.json +++ b/instances.json @@ -43,6 +43,20 @@ "branch": "dev" } } + ], + [ + "poke.ashley0143.xyz", + { + "uri": "https://poke.ashley0143.xyz", + "CLOUDFLARE": true, + "piwik": false, + "region": "🇺🇸", + "software": { + "name": "poketube", + "version": "latest", + "branch": "dev" + } + } ] ] diff --git a/p/server.js b/p/server.js index fdad6585..f3e65d46 100644 --- a/p/server.js +++ b/p/server.js @@ -48,7 +48,7 @@ app.use(function (req, res, next) { app.use(function (_req, res, next) { res.header("Access-Control-Allow-Origin", "*"); - res.setHeader("Cache-Control", "public, max-age=232337763"); // cache header + res.setHeader("Cache-Control", "public, max-age=864000"); // cache header res.setHeader("poketube-cacher", "PROXY_FILES"); next(); @@ -60,7 +60,7 @@ app.use(function (_req, res, next) { */ const proxy = async (req, res) => { const { fetch } = await import("undici") - res.setHeader("Cache-Control", "public, max-age=232337763"); // cache header + res.setHeader("Cache-Control", "public, max-age=864000"); // cache header try { let url; @@ -98,9 +98,9 @@ const listener = (req, res) => { app.get("/", (req, res) => { var json = { status: "200", - version: "1.2.0", + version: "1.3.0", URL_WHITELIST, - cache: "max-age-232337763", + cache: "max-age-864000", }; res.json(json); diff --git a/package.json b/package.json index 69dcffa7..d7cf5bf9 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { - "name": "poketube", - "version": "20.23", - "description": "Libre youtube front-end", + "name": "poke", + "version": "20.24", + "description": "Libre youtube and google front-end", "main": "server.js", "scripts": { "start": "node server.js" @@ -32,7 +32,8 @@ "express-rate-limit": "^7.0.2", "toobusy-js": "^0.5.1", "quick.db": "^7.1.3", - "google-it": "^1.6.4" + "activitypub-express": "^4.4.1", + "duck-duck-scrape": "^2.2.5" }, "engines": { "node": "16.x" @@ -43,7 +44,7 @@ "license": "GPL-3.0-or-later", "keywords": [ "poketube", - "privite", + "private", "ytdl" ] } \ No newline at end of file diff --git a/poke-cli.sh b/poke-cli.sh new file mode 100644 index 00000000..7ec48bb7 --- /dev/null +++ b/poke-cli.sh @@ -0,0 +1,127 @@ +#!/usr/bin/env bash +# +# Copyright (C) 2024-20xx Poke! (https://codeberg.org/ashley/poke) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +function display_help { + echo "Usage: $0 " + echo " --help you are here lol" + echo " --version version information." + echo " --license license stuff" +} + +function display_version { +echo "poke-cli version 1.2 + +Play videos from your terminal! +https://codeberg.org/ashley/poke + +Copyright (C) 2024-202x Poke +License GPLv3+: GNU GPL version 3 or later . +This is free software: you are free to change and redistribute it. +There is NO WARRANTY, to the extent permitted by law. +" +} + +# Display license information +function display_license { + cat <. + +EOF +} + +case $1 in + --help) + display_help + exit 0 + ;; + --version) + display_version + exit 0 + ;; + --license) + display_license + exit 0 + ;; +esac + +if [ $# -eq 0 ]; then + echo "Usage: $0 / see --help for more info :D" + exit 1 +fi + +# config +poke_instance="https://poketube.fun" +invid_api_url="https://invid-api.poketube.fun" + +search_query=$1 + +player="mpv" + + +if ! command -v jq &> /dev/null && ! command -v gojq &> /dev/null; then + echo "Error: jq or gojq not found. Please install them to run the script." + exit 1 +fi + +json_data=$(curl -s "$invid_api_url/api/v1/search?q=${search_query// /+}&type=video") + +video_count=$(echo "$json_data" | jq -r '. | length') +if [ $video_count -eq 0 ]; then + echo "Nyo videos found for the given search query ;_;" + exit 1 +fi + +echo "Select a vid to play:" +echo + +for i in $(seq 0 $(($video_count - 1))); do + title=$(echo "$json_data" | jq -r ".[$i].title") + author=$(echo "$json_data" | jq -r ".[$i].author") + echo "[$(($i + 1))] $title by $author" +done + +read -p "Enter the thingy umm number of the video to play (1-$video_count): " selection + +if ! [[ "$selection" =~ ^[1-9][0-9]*$ ]] || [ "$selection" -lt 1 ] || [ "$selection" -gt "$video_count" ]; then + echo "enter a number between 1 and $video_count lol" + exit 1 +fi + +video_url=$(echo "$json_data" | jq -r ".[$(($selection - 1))].videoId") + +echo "Starting $player..." +echo "please wait - this may take some time lol..." + +$player "$poke_instance/watch?v=$video_url" + diff --git a/pwa/offline.html b/pwa/offline.html index 3aa7c5fb..12379df3 100644 --- a/pwa/offline.html +++ b/pwa/offline.html @@ -16,21 +16,36 @@ You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/. --> - - - PokeTube - + + + + Poke - No interenet!1!1!1!111! +
-

Oh no ;-;

-

Looks like you're offline, check your internet connection and try again.

+

Oh nyo >~<

+

Connectivity to the server has been lost qwq
Seems like you're offline - u check your internet connection and try again


+

or u can just view poke!'s status page yk~

+
+
- - \ No newline at end of file + diff --git a/pwa/service-worker.js b/pwa/service-worker.js index 2ce1c1d8..d34e1859 100644 --- a/pwa/service-worker.js +++ b/pwa/service-worker.js @@ -1,3 +1,5 @@ +// @license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-3.0-or-later + 'use strict'; var cacheVersion = 1; @@ -31,4 +33,6 @@ this.addEventListener('fetch', event => { }) ); } -}); \ No newline at end of file +}); + +// @license-end \ No newline at end of file diff --git a/server.js b/server.js index 8189550f..76a19d8a 100644 --- a/server.js +++ b/server.js @@ -2,7 +2,7 @@ PokeTube is an Free/Libre youtube front-end. this is our main file. - Copyright (C) 2021-2023 POKETUBE (https://codeberg.org/Ashley/poketube) + Copyright (C) 2021-2024 POKETUBE (https://codeberg.org/Ashley/poketube) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -35,7 +35,7 @@ const u = await media_proxy(); initlog("Loading..."); initlog( - "[Welcome] Welcome To PokeTube :3 " + + "[Welcome] Welcome To Poke - The ultimate privacy app - :3 " + "Running " + `Node ${process.version} - V8 v${ process.versions.v8 @@ -65,8 +65,8 @@ const limiter = rateLimit({ - windowMs:45 * 1000, // 30 Seconds - max: 886, // limit each IP to 870 requests per windowMs + windowMs:45 * 1000, // 45 Seconds + max: 886, // limit each IP to 866 requests per windowMs }); var app = modules.express(); @@ -101,6 +101,7 @@ toobusy.maxLag(3500); }); toobusy.onLag(function(currentLag) { + process.exit(1); console.log("Event loop lag detected! Latency: " + currentLag + "ms"); }); @@ -136,6 +137,9 @@ toobusy.maxLag(3500); } res.header("secure-poketube-instance", "1"); + // opt out of googles "FLOC" bullcrap :p See https://spreadprivacy.com/block-floc-with-duckduckgo/ + res.header("Permissions-Policy", "interest-cohort=()") + res.header("software-name", "poke") next(); }); @@ -157,8 +161,9 @@ toobusy.maxLag(3500); app.use(function (req, res, next) { res.header("X-PokeTube-Youtube-Client-Name", "1"); - res.header("X-PokeTube-Youtube-Client-Version", "2.20210721.00.00"); - res.header("X-PokeTube-Speeder", "6 seconds no cache, 780ms w/cache"); + res.header("Hey-there", "Do u wanna help poke? contributons are welcome :3 https://codeberg.org/Ashley/poke") + res.header("X-PokeTube-Youtube-Client-Version", "2.20240111.00.00"); + res.header("X-PokeTube-Speeder", "3 seconds no cache, 280ms w/cache"); if (req.url.match(/^\/(css|js|img|font)\/.+/)) { res.setHeader( "Cache-Control", diff --git a/src/libpoketube/init/pages-404-and-main.js b/src/libpoketube/init/pages-404-and-main.js index 783cae32..695d1c75 100644 --- a/src/libpoketube/init/pages-404-and-main.js +++ b/src/libpoketube/init/pages-404-and-main.js @@ -130,8 +130,13 @@ module.exports = function (app, config, renderTemplate) { if (req.params.v && /[a-zA-Z0-9]+/.test(req.params.v)) { const isvld = await core.isvalidvideo(req.params.v); - if (isvld) { + if (isvld && req.params.v.length >= 10) { return res.redirect(`/watch?v=${req.params.v}`); + } else { + return renderTemplate(res, req, "404.ejs", { + isOldWindows, + random + }); } } diff --git a/src/libpoketube/init/pages-api.js b/src/libpoketube/init/pages-api.js index f0507028..e557e214 100644 --- a/src/libpoketube/init/pages-api.js +++ b/src/libpoketube/init/pages-api.js @@ -29,12 +29,12 @@ function getJson(str) { const pkg = require("../../../package.json"); const cnf = require("../../../config.json"); -const verfull = "v23.1311-JeSsIcA-MAJOR-stable-dev-nonLTS-git-MTcwMDI5ODc4OQ=="; -const versmol = "v23.1311-JeSsIcA" +const verfull = "v24.2801-JeSsIcA-MAJOR-stable-dev-nonLTS-git-MTcwNjQzMTc0OQ=="; +const versmol = "v24.2801-JeSsIcA" const branch = "dev/master"; const codename = "jessica"; -const versionnumber = "272"; -const relaseunixdate = "MTcwMDI5ODc4OQ==" +const versionnumber = "273"; +const relaseunixdate = "MTcwNjQzMTc0OQ==" const updatequote = "Empty your cup so that it may be filled; become devoid to gain totality. - Bruce Lee" @@ -52,7 +52,7 @@ module.exports = function (app, config, renderTemplate) { }); app.get("/vi/:v/:t", async function (req, res) { - var url = `https://invidious.snopyta.org/vi/${req.params.v}/${req.params.t}` + var url = `https://vid.puffyan.us/vi/${req.params.v}/${req.params.t}` let f = await modules.fetch(url + `?cachefixer=${btoa(Date.now())}`, { method: req.method, @@ -63,7 +63,7 @@ module.exports = function (app, config, renderTemplate) { }); app.get("/avatars/:v", async function (req, res) { - var url = `https://invidious.snopyta.org/ggpht/${req.params.v}`; + var url = `https://vid.puffyan.us/ggpht/${req.params.v}`; let f = await modules.fetch(url + `?cachefixer=${btoa(Date.now())}`, { method: req.method, @@ -73,7 +73,7 @@ app.get("/avatars/:v", async function (req, res) { }); app.get("/ggpht/:v", async function (req, res) { - var url = `https://invidious.snopyta.org/ggpht/${req.params.v}`; + var url = `https://vid.puffyan.us/ggpht/${req.params.v}`; let f = await modules.fetch(url + `?cachefixer=${btoa(Date.now())}`, { method: req.method, @@ -84,7 +84,7 @@ app.get("/avatars/:v", async function (req, res) { app.get("/avatars/ytc/:v", async function (req, res) { - var url = `https://invidious.snopyta.org/ggpht/ytc/${req.params.v.replace("ytc", "")}`; + var url = `https://vid.puffyan.us/ggpht/ytc/${req.params.v.replace("ytc", "")}`; let f = await modules.fetch(url + `?cachefixer=${btoa(Date.now())}`, { method: req.method, @@ -114,7 +114,7 @@ app.get("/avatars/:v", async function (req, res) { var format = "mp3"; } - const url = `https://tube-proxy.poketube.fun/proxy/media/${v}/${q}`; + const url = `https://tube.kuylar.dev/proxy/media/${v}/${q}`; res.redirect(url); }); diff --git a/src/libpoketube/init/pages-channel-and-download.js b/src/libpoketube/init/pages-channel-and-download.js index 65d3a400..3f6f628c 100644 --- a/src/libpoketube/init/pages-channel-and-download.js +++ b/src/libpoketube/init/pages-channel-and-download.js @@ -44,15 +44,16 @@ function getJson(str) { * @property {string} streams - Base64-encoded value for the streams tab. */ -// see https://developers.google.com/youtube/v3/docs/channels/ +// see https://developers.google.com/youtube/v3/docs/channels/ const ChannelTabs = { community: "Y29tbXVuaXR5", shorts: "c2hvcnRz", videos: "dmlkZW9z", streams: "c3RyZWFtcw==", // or "live" - channels:"Y2hhbm5lbHM=", - store:"c3RvcmU=", - released:"cmVsZWFzZWQ=" + channels: "Y2hhbm5lbHM=", + store: "c3RvcmU=", + released: "cmVsZWFzZWQ=", + playlist: "cGxheWxpc3Rz", }; module.exports = function (app, config, renderTemplate) { @@ -80,18 +81,20 @@ module.exports = function (app, config, renderTemplate) { res.redirect(`/watch?v=${v}`); }); - app.get("/api/getchanneltabs", async function (req, res) { + app.get("/api/getchanneltabs", async function (req, res) { res.json(ChannelTabs); }); - app.get("/search", async (req, res) => { const query = req.query.query; const tab = req.query.tab; const { fetch } = await import("undici"); - const search = require("google-it"); + var media_proxy = config.media_proxy; + if (req.useragent.source.includes("Pardus")) { + var media_proxy = "https://media-proxy.ashley0143.xyz"; + } var uaos = req.useragent.os; var IsOldWindows; @@ -128,19 +131,23 @@ module.exports = function (app, config, renderTemplate) { let type = "video"; let duration = req.query.duration || ""; let sort = req.query.sort || ""; - + try { const headers = {}; - const xmlData = await fetch(`https://invid-api.poketube.fun/api/v1/search?q=${encodeURIComponent( - query - )}&page=${encodeURIComponent(continuation)}&date=${date}&type=${type}&duration=${duration}&sort=${sort}&hl=en+gb`) - .then((res) => res.text()) - .then((txt) => getJson(txt)); - + const xmlData = await fetch( + `https://invid-api.poketube.fun/api/v1/search?q=${encodeURIComponent( + query + )}&page=${encodeURIComponent( + continuation + )}&date=${date}&type=${type}&duration=${duration}&sort=${sort}&hl=en+gb` + ) + .then((res) => res.text()) + .then((txt) => getJson(txt)); + renderTemplate(res, req, "search.ejs", { invresults: xmlData, - turntomins, + turntomins, date, type, duration, @@ -148,7 +155,7 @@ module.exports = function (app, config, renderTemplate) { IsOldWindows, tab, continuation, - media_proxy_url: config.media_proxy, + media_proxy_url: media_proxy, results: "", q: query, summary: "", @@ -159,12 +166,24 @@ module.exports = function (app, config, renderTemplate) { } }); + app.get("/im-feeling-lucky", function (req, res) { + res.send("WIP"); + }); + app.get("/web", async (req, res) => { const query = req.query.query; const tab = req.query.tab; - const search = require("google-it"); + const { fetch } = await import("undici"); + const search = await fetch( + `https://4get.sudovanilla.com/api/v1/web?s=${query}` + ); + const web = getJson(await search.text()); + + if (req.query.lucky === "true") { + res.redirect("/im-feeling-lucky?query=" + query); + } var uaos = req.useragent.os; var IsOldWindows; @@ -199,18 +218,18 @@ module.exports = function (app, config, renderTemplate) { let continuation = req.query.continuation || ""; try { - search({ query: `${req.query.query}` }).then((results) => { - renderTemplate(res, req, "search-web.ejs", { - j: "", - IsOldWindows, - h: "", - tab, - continuation, - isMobile: req.useragent.isMobile, - results: results, - q: query, - summary: "", - }); + const results = web.web; + + renderTemplate(res, req, "search-web.ejs", { + j: "", + IsOldWindows, + h: "", + tab, + continuation, + isMobile: req.useragent.isMobile, + results: results, + q: query, + summary: "", }); } catch (error) { console.error(`Error while searching for '${query}':`, error); @@ -221,7 +240,21 @@ module.exports = function (app, config, renderTemplate) { app.get("/channel/", async (req, res) => { const { fetch } = await import("undici"); try { - const ID = req.query.id; + var media_proxy = config.media_proxy; + + if (req.useragent.source.includes("Pardus")) { + var media_proxy = "https://media-proxy.ashley0143.xyz"; + } + + var ID = req.query.id; + + if (ID.endsWith("@youtube.com")) { + ID = ID.slice(0, -"@youtube.com".length); + } + + if (ID.endsWith("@poketube.fun")) { + ID = ID.slice(0, -"@poketube.fun".length); + } const tab = req.query.tab; const cache = {}; @@ -268,17 +301,33 @@ module.exports = function (app, config, renderTemplate) { const communityUrl = `${apiUrl}${atob( ChannelTabs.community )}/${ID}/?hl=en-US`; + const PlaylistUrl = `${apiUrl}${atob( + ChannelTabs.playlist + )}/${ID}/?hl=en-US`; const channelINVUrl = `${apiUrl}${ID}/`; - var [tj, shorts, stream, c, cinv] = await Promise.all([ + var [tj, shorts, playlist, stream, c, cinv] = await Promise.all([ getChannelData(channelUrl), getChannelData(shortsUrl), + getChannelData(PlaylistUrl), getChannelData(streamUrl), getChannelData(communityUrl), getChannelData(channelINVUrl), ]); + function getThumbnailUrl(video) { + const maxresDefaultThumbnail = video.videoThumbnails.find( + (thumbnail) => thumbnail.quality === "maxresdefault" + ); + + if (maxresDefaultThumbnail) { + return `https://vid.puffyan.us/vi/${video.videoId}/maxresdefault.jpg`; + } else { + return `https://vid.puffyan.us/vi/${video.videoId}/hqdefault.jpg`; + } + } + cache[ID] = { result: { tj, @@ -315,13 +364,15 @@ module.exports = function (app, config, renderTemplate) { cinv, convert, turntomins, - media_proxy_url: config.media_proxy, + media_proxy_url: media_proxy, dnoreplace, + getThumbnailUrl, continuation, wiki: "", getFirstLine, isMobile: req.useragent.isMobile, about, + playlist, subs: typeof subscribers === "string" ? subscribers.replace("subscribers", "") diff --git a/src/libpoketube/init/pages-static.js b/src/libpoketube/init/pages-static.js index 31467383..af32f317 100644 --- a/src/libpoketube/init/pages-static.js +++ b/src/libpoketube/init/pages-static.js @@ -27,6 +27,13 @@ const sha384 = modules.hash; const notice = "/* the code is Licensed in gpl-3.0-or-later. This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. See the GNU General Public License for more detailsYou should have received a copy of the GNU General Public Licensealong with this program. If not, see . - add the param nomin to view source code. (eg poketube.fun/css/poketube.css?nomin=true) */"; +function getJson(str) { + try { + return JSON.parse(str); + } catch { + return null; + } +} module.exports = function (app, config, renderTemplate) { var html_location = "./css/"; var location_pwa = "./pwa/"; @@ -67,39 +74,85 @@ module.exports = function (app, config, renderTemplate) { } }); + app.get("/rewind", function (req, res) { + renderTemplate(res, req, "rewind.ejs"); + }); + + app.get("/translate", async function (req, res) { + const { fetch } = await import("undici"); + + const api_url = "https://simplytranslate.org/api/translate"; + + // Fetch translation data + const translationResponse = await fetch( + `${api_url}?from=${req.query.from_language}&to=${req.query.to_language}&text=${req.query.input}&engine=google` + ); + + // Check if the request was successful (status code 200) + const translationData = await translationResponse.json(); + + // Extract translated_text from the response + const translatedText = translationData.translated_text; + + // Render the template with the translated text + renderTemplate(res, req, "translate.ejs", { + translation: translatedText, + text: req.query.input || "enter text here", + from_language: req.query.from_language, + to_language: req.query.to_language, + isMobile: req.useragent.isMobile, + }); + }); + app.get("/domains", function (req, res) { renderTemplate(res, req, "domains.ejs"); }); + app.get("/apps", function (req, res) { + renderTemplate(res, req, "apps.ejs"); + }); + app.get("/playlist", async function (req, res) { + const { fetch } = await import("undici"); + if (!req.query.list) res.redirect("/"); + if (req.useragent.isMobile) res.redirect("/"); + + const playlist = await fetch( + `https://invid-api.poketube.fun/api/v1/playlists/${req.query.list}?hl=en-us` + ); + + const p = getJson(await playlist.text()); + var mediaproxy = config.media_proxy; + + renderTemplate(res, req, "playlist.ejs", { + p, + mediaproxy, + }); + }); + app.get("/license", function (req, res) { renderTemplate(res, req, "license.ejs"); }); - app.get("/map", function (req, res) { + app.get("/map", function (req, res) { renderTemplate(res, req, "map.ejs"); }); - + app.get("/credits", function (req, res) { renderTemplate(res, req, "want-you-gone.ejs"); }); - + app.get("/settings", function (req, res) { renderTemplate(res, req, "content-settings.ejs"); }); - + app.get("/offline", function (req, res) { res.sendFile("offline.html", { root: location_pwa }); }); - + app.get("/manifest.json", function (req, res) { res.sendFile("manifest.json", { root: location_pwa }); }); - - app.get("/service-worker.js", function (req, res) { - res.sendFile("service-worker.js", { root: location_pwa }); - }); - app.get("/customize", function (req, res) { const tab = req.query.tab; @@ -110,6 +163,10 @@ module.exports = function (app, config, renderTemplate) { const cssDir = "./css/"; + app.get("/favicon.ico", function (req, res) { + res.sendFile("favicon.ico", { root: cssDir }); + }); + app.get("/css/:id", (req, res) => { const filePath = path.join(cssDir, req.params.id); if (!fs.existsSync(filePath)) { @@ -123,7 +180,11 @@ module.exports = function (app, config, renderTemplate) { const minimizedCss = new CleanCSS().minify(css).styles; // Serve the minimized CSS file res.header("Content-Type", "text/css"); - res.send(notice + " " + minimizedCss); + res.send( + notice + + " " + + minimizedCss.replace("https://p.poketube.fun", config.p_url) + ); } else { // Serve the original file res.sendFile(req.params.id, { root: html_location }); @@ -134,59 +195,64 @@ module.exports = function (app, config, renderTemplate) { } }); -app.get("/static/:id", (req, res) => { - const id = req.params.id; + app.get("/game-hub", function (req, res) { + renderTemplate(res, req, "gamehub.ejs", { + game: req.query.game, + }); + }); + app.get("/static/:id", (req, res) => { + const id = req.params.id; - if (id.endsWith(".css")) { - res.redirect("/css/" + id); - } else if (id.endsWith(".js")) { - if (id.endsWith(".bundle.js")) { - const jsFiles = ['app.js', 'custom-css.js', 'emojis.js']; - const combinedContent = jsFiles - .map((fileName) => { - const filePath = path.join(html_location, fileName); - return fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf-8') : ''; - }) - .join('\n'); + if (id.endsWith(".css")) { + res.redirect("/css/" + id); + } else if (id.endsWith(".js")) { + if (id.endsWith(".bundle.js")) { + const jsFiles = ["app.js", "custom-css.js", "emojis.js"]; + const combinedContent = jsFiles + .map((fileName) => { + const filePath = path.join(html_location, fileName); + return fs.existsSync(filePath) + ? fs.readFileSync(filePath, "utf-8") + : ""; + }) + .join("\n" + "\n"); - const minimizedJs = require("uglify-js").minify(combinedContent).code; + const minimizedJs = require("uglify-js").minify(combinedContent).code; - res.header("Content-Type", "text/javascript"); - res.send( - "// @license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-3.0-or-later" + - `\n` + - `// Includes app.js, emojis.js, and custom-css.js. Source code can be found for these 3 files in https://codeberg.org/Ashley/poketube/src/branch/main/css/` + - `\n` + - minimizedJs + - `\n` + - "// @license-end" - ); - } else { - const filePath = path.join(html_location, id); + res.header("Content-Type", "text/javascript"); + res.send( + "// @license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-3.0-or-later" + + `\n` + + `// Includes app.js, emojis.js, and custom-css.js. Source code can be found for these 3 files in https://codeberg.org/Ashley/poketube/src/branch/main/css/` + + `\n` + + minimizedJs + + `\n` + + "// @license-end" + ); + } else { + const filePath = path.join(html_location, id); - if (!fs.existsSync(filePath)) { - res.status(404).send("File not found"); - return; + if (!fs.existsSync(filePath)) { + res.status(404).send("File not found"); + return; + } + + const js = fs.readFileSync(filePath, "utf8"); + const minimizedJs = require("uglify-js").minify(js).code; + + res.header("Content-Type", "text/javascript"); + res.send( + "// @license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-3.0-or-later" + + `\n` + + `// Source code can be found in: https://codeberg.org/Ashley/poketube/src/branch/main/css/${id}` + + `\n` + + minimizedJs + + `\n` + + "// @license-end" + ); } - - const js = fs.readFileSync(filePath, "utf8"); - const minimizedJs = require("uglify-js").minify(js).code; - - res.header("Content-Type", "text/javascript"); - res.send( - "// @license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-3.0-or-later" + - `\n` + - `// Source code can be found in: https://codeberg.org/Ashley/poketube/src/branch/main/css/${id}` + - `\n` + - minimizedJs + - `\n` + - "// @license-end" - ); + } else { + res.sendFile(id, { root: html_location }); } - } else { - res.sendFile(id, { root: html_location }); - } -}); - - + }); }; diff --git a/src/libpoketube/init/pages-video.js b/src/libpoketube/init/pages-video.js index f8e3e007..0405b431 100644 --- a/src/libpoketube/init/pages-video.js +++ b/src/libpoketube/init/pages-video.js @@ -139,6 +139,11 @@ function lightOrDark(color) { } } +function isDntEnabled(req) { + const dntHeader = req.header('DNT'); + return dntHeader && (dntHeader === '1' || dntHeader === 'true'); +} + function IsInArray(array, id) { for (var i = 0; i < array.length; i++) { if (array[i].id === id) return true; @@ -178,19 +183,7 @@ module.exports = function (app, config, renderTemplate) { }); app.get("/watch", async (req, res) => { - const { - dm, - region, - hl, - v, - e, - r, - f, - m, - quality: q, - a, - universe, - } = req.query; + const { dm, region, hl, v, e, r, f, m, quality: q, a, universe, } = req.query; if (!v) { return res.redirect("/"); @@ -208,10 +201,11 @@ module.exports = function (app, config, renderTemplate) { const secure = ["poketube.fun"].includes(req.hostname); const verify = req.hostname === "poketube.sudovanilla.com"; - + core.video(v, contentlang, contentregion).then((data) => { try { const k = data?.video; + const channel_uploads = data?.channel_uploads const json = data?.json; const engagement = data?.engagement; const inv_comments = data?.comments || "Disabled"; @@ -222,6 +216,7 @@ module.exports = function (app, config, renderTemplate) { if (desc !== "[object Object]") { d = desc.toString().replace(/\n/g, "
"); } + const descriptionString = String(inv_vid?.description); @@ -237,28 +232,35 @@ module.exports = function (app, config, renderTemplate) { const twitch = extractInfo(TWITCH_REGEX); const reddit = extractInfo(REDDIT_REGEX); const instagram = extractInfo(INSTAGRAM_REGEX); - + + + var proxyurl = config.p_url; var vidurl = u.url; var isvidious = u.isInvidiousURL; - + var mediaproxy = config.media_proxy + + if (inv_vid?.genre === "Music") { var vidurl = u.losslessurl; } - if (inv_vid.author.endsWith(" - Topic")) { - var vidurl = "https://eu-proxy.poketube.fun"; - var isvidious = true; - } + var vidurl = "https://eu-proxy.poketube.fun"; + var isvidious = true; if (req.useragent.source.includes("Pardus")) { - var vidurl = "https://yt.sudovanilla.com"; + var vidurl = "https://iv.ggtyler.dev"; + var mediaproxy = "https://media-proxy.ashley0143.xyz" var isvidious = true; + var isSchoolProxy = ""; } - + + // unused let badges = ""; let comments = ""; let nnn = ""; + const dnt_val = isDntEnabled(req) + if ( inv_vid?.error === "The uploader has not made this video available in your country" || @@ -299,15 +301,20 @@ module.exports = function (app, config, renderTemplate) { twitter, k, dm, - media_proxy_url: config.media_proxy, + proxyurl, + media_proxy_url: mediaproxy, instagram, useragent: req.useragent, verify, discord, + turntomins, twitch, + dnt_val, reddit, + channel_uploads, secure, process, + isSchoolProxy, sha384, lightOrDark, isMobile: req.useragent.isMobile, @@ -342,8 +349,7 @@ module.exports = function (app, config, renderTemplate) { const { v, e, r, f, t, quality: q } = req.query; try { - const info = await modules.fetch("http://ip-api.com/json/"); - const ip = await info.json(); + var mediaproxy = config.media_proxy const { video: k, @@ -363,11 +369,13 @@ module.exports = function (app, config, renderTemplate) { const u = await media_proxy(v); const d = desc.toString().replace(/\n/g, "
"); const comments = inv_comments || "Disabled"; - + const channel_uploads = data?.channel_uploads + const templateData = { color, color2, engagement, + channel_uploads, u: u.url, video: json, date: k.Video.uploadDate, @@ -378,11 +386,12 @@ module.exports = function (app, config, renderTemplate) { lightOrDark, isMobile, tj, + media_proxy_url: mediaproxy, r, qua: q, isvidious: u.isInvidiousURL, inv: comments, - ip, + turntomins, convert, linkify, wiki, @@ -552,4 +561,4 @@ module.exports = function (app, config, renderTemplate) { } } }); -}; +}; \ No newline at end of file diff --git a/src/libpoketube/libpoketube-core.js b/src/libpoketube/libpoketube-core.js index 826354bb..ff265d87 100644 --- a/src/libpoketube/libpoketube-core.js +++ b/src/libpoketube/libpoketube-core.js @@ -10,7 +10,6 @@ const { toJson } = require("xml2json"); const { curly } = require("node-libcurl"); const getdislikes = require("../libpoketube/libpoketube-dislikes.js"); const getColors = require("get-image-colors"); -const wiki = require("wikipedia"); /** * Class representing PokeTube's core functionality. @@ -79,8 +78,8 @@ class PokeTubeCore { try { const [invComments, videoInfo, videoData] = await Promise.all([ - fetch(`${this.config.invapi}/comments/${v}?hl=${contentlang}®ion=${contentregion}&h=${btoa(Date.now())}`).then((res) => res.text()), - fetch(`${this.config.invapi}/videos/${v}?hl=${contentlang}®ion=${contentregion}&h=${btoa(Date.now())}`).then((res) => res.text()), + fetch(`${this.config.invapi_alt}/comments/${v}?hl=${contentlang}®ion=${contentregion}&h=${btoa(Date.now())}`).then((res) => res.text()), + fetch(`${this.config.invapi_alt}/videos/${v}?hl=${contentlang}®ion=${contentregion}&h=${btoa(Date.now())}`).then((res) => res.text()), curly .get(`${this.config.tubeApi}video?v=${v}`, { httpHeader: Object.entries(headers).map(([k, v]) => `${k}: ${v}`), @@ -96,6 +95,11 @@ class PokeTubeCore { const vid = await this.getJson(videoInfo); const { json, video } = videoData; + const channel_uploads = await fetch( + `${this.config.invapi_alt}/channels/${vid.authorId}?hl=${contentlang}®ion=${contentregion}` + ); + const p = this.getJson(await channel_uploads.text()); + if (!vid) { console.log( `Sorry nya, we couldn't find any information about that video qwq` @@ -115,14 +119,15 @@ class PokeTubeCore { video, vid, comments, + channel_uploads:p, engagement: fe.engagement, wiki: "", desc: "", color: await getColors( - `https://i.ytimg.com/vi/${v}/hqdefault.jpg?sqp=${this.sqp}` + `https://vid.puffyan.us/vi/${v}/hqdefault.jpg?sqp=${this.sqp}` ).then((colors) => colors[0].hex()), color2: await getColors( - `https://i.ytimg.com/vi/${v}/hqdefault.jpg?sqp=${this.sqp}` + `https://vid.puffyan.us/vi/${v}/hqdefault.jpg?sqp=${this.sqp}` ).then((colors) => colors[1].hex()), }, timestamp: Date.now(), @@ -166,6 +171,7 @@ class PokeTubeCore { const pokeTubeApiCore = new PokeTubeCore({ tubeApi: "https://inner-api.poketube.fun/api/", invapi: "https://invid-api.poketube.fun/api/v1", + invapi_alt: "https://iv.ggtyler.dev/api/v1", dislikes: "https://returnyoutubedislikeapi.com/votes?videoId=", t_url: "https://t.poketube.fun/", }); diff --git a/src/libpoketube/ptutils/libpt-coreutils.js b/src/libpoketube/ptutils/libpt-coreutils.js index 013d8224..e4a9e853 100644 --- a/src/libpoketube/ptutils/libpt-coreutils.js +++ b/src/libpoketube/ptutils/libpt-coreutils.js @@ -2,7 +2,7 @@ PokeTube is a Free/Libre youtube front-end ! - Copyright (C) 2021-2022 POKETUBE + Copyright (C) 2021-2024 POKETUBE This file is Licensed under LGPL-3.0-or-later. Poketube itself is GPL, Only this file is LGPL. @@ -12,6 +12,11 @@ */ +/** + * Checks if a string is a valid JSON. + * @param {string} str - The string to be checked. + * @returns {boolean} - Returns true if the string is a valid JSON, otherwise false. + */ function IsJsonString(str) { try { JSON.parse(str); @@ -21,50 +26,87 @@ function IsJsonString(str) { return true; } +/** + * Converts a number into a compact string representation using the en-GB locale. + * @param {number} value - The number to be converted. + * @returns {string} - The compact string representation of the number. + */ function convert(value) { return new Intl.NumberFormat("en-GB", { notation: "compact", }).format(value); } +/** + * Extracts the first line of text before the first occurrence of "
". + * @param {string} text - The input text. + * @returns {string} - The first line of text before "
", or the entire text if no "
" is found. + */ function getFirstLine(text) { var index = text?.indexOf("
"); if (index === -1) index = undefined; return text?.substring(0, index); } +/** + * Capitalizes the first letter of a string. + * @param {string} string - The input string. + * @returns {string} - The string with the first letter capitalized. + */ function capitalizeFirstLetter(string) { return string.charAt(0).toUpperCase() + string.slice(1); } +/** + * Converts time in seconds to a formatted time string (hh:mm:ss or mm:ss). + * If time is 00:00, returns "LIVE". + * @param {number} time - The time in seconds. + * @returns {string} - The formatted time string. + */ function turntomins(time) { - var minutes = Math.floor(time / 60); - - var seconds = time - minutes * 60; + var hours = Math.floor(time / 3600); + var remainingSeconds = time - hours * 3600; + var minutes = Math.floor(remainingSeconds / 60); + var seconds = remainingSeconds - minutes * 60; function str_pad_left(string, pad, length) { return (new Array(length + 1).join(pad) + string).slice(-length); } - var finalTime = - str_pad_left(minutes, "0", 2) + ":" + str_pad_left(seconds, "0", 2); + if (hours > 0) { + var finalTime = + str_pad_left(hours, "0", 2) + + ":" + + str_pad_left(minutes, "0", 2) + + ":" + + str_pad_left(seconds, "0", 2); + } else { + if (minutes === 0 && seconds === 0) { + return "LIVE"; + } else { + var finalTime = + str_pad_left(minutes, "0", 2) + ":" + str_pad_left(seconds, "0", 2); + } + } return finalTime; -}; +} /** - * Returns a random number between min (inclusive) and max (exclusive) + * Returns a random floating point number within the specified range. + * @param {number} min - The minimum value of the range (inclusive). + * @param {number} max - The maximum value of the range (exclusive). + * @returns {number} - A random floating point number within the specified range. */ function getRandomArbitrary(min, max) { return Math.random() * (max - min) + min; } /** - * Returns a random integer between min (inclusive) and max (inclusive). - * The value is no lower than min (or the next integer greater than min - * if min isn't an integer) and no greater than max (or the next integer - * lower than max if max isn't an integer). - * Using Math.round() will give you a non-uniform distribution! + * Returns a random integer within the specified range. + * @param {number} min - The minimum value of the range (inclusive). + * @param {number} max - The maximum value of the range (inclusive). + * @returns {number} - A random integer within the specified range. */ function getRandomInt(min, max) { min = Math.ceil(min); @@ -72,6 +114,12 @@ function getRandomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } +/** + * Increases or decreases the brightness of a hexadecimal color code. + * @param {string} hex - The hexadecimal color code. + * @param {number} percent - The percentage by which to adjust the brightness (positive for increase, negative for decrease). + * @returns {string} - The modified hexadecimal color code. + */ function increase_brightness(hex, percent){ // strip the leading # if it's there hex = hex.replace(/^\s*#|\s*$/g, ''); @@ -91,12 +139,92 @@ function increase_brightness(hex, percent){ ((0|(1<<8) + b + (256 - b) * percent / 100).toString(16)).substr(1); } +/** + * Converts an array to an object with numeric keys. + * @param {Array} arr - The input array. + * @returns {Object} - The resulting object with numeric keys. + */ +function toObject(arr) { + var rv = {}; + for (var i = 0; i < arr.length; ++i) if (arr[i] !== undefined) rv[i] = arr[i]; + return rv; +} + +/** + * Determines if a color is light or dark. + * @param {string} color - The color code in hexadecimal or RGB format. + * @returns {string} - Returns "light" if the color is light, otherwise "dark". + */ +function lightOrDark(color) { + // Variables for red, green, blue values + var r, g, b, hsp; + + // Check the format of the color, HEX or RGB? + if (color.match(/^rgb/)) { + // If RGB --> store the red, green, blue values in separate variables + color = color.match( + /^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d+)?))?\)$/ + ); + + r = color[1]; + g = color[2]; + b = color[3]; + } else { + // If hex --> Convert it to RGB: http://gist.github.com/983661 + color = +("0x" + color.slice(1).replace(color.length < 5 && /./g, "$&$&")); + + r = color >> 16; + g = (color >> 8) & 255; + b = color & 255; + } + + // HSP (Highly Sensitive Poo) equation from http://alienryderflex.com/hsp.html + hsp = Math.sqrt(0.299 * (r * r) + 0.587 * (g * g) + 0.114 * (b * b)); + + // Using the HSP value, determine whether the color is light or dark + if (hsp > 127.5) { + return "light"; + } else { + return "dark"; + } +} + +/** + * Checks if an element with a specific ID exists in an array of objects. + * @param {Array} array - The array of objects to be searched. + * @param {string} id - The ID to search for. + * @returns {boolean} - Returns true if the ID exists in the array, otherwise false. + */ +function IsInArray(array, id) { + for (var i = 0; i < array.length; i++) { + if (array[i].id === id) return true; + } + return false; +} + +/** + * Parses a JSON string into a JavaScript object. + * @param {string} str - The JSON string to be parsed. + * @returns {(Object|boolean)} - Returns the parsed JavaScript object if successful, otherwise false. + */ +function getJson(str) { + try { + return JSON.parse(str); + } catch { + return false; + } +} + module.exports = { -IsJsonString, -convert, -getFirstLine, -getRandomArbitrary, -getRandomInt, -capitalizeFirstLetter, -turntomins -}; \ No newline at end of file + IsJsonString, + convert, + getFirstLine, + getRandomArbitrary, + getJson, + lightOrDark, + toObject, + IsInArray, + getRandomInt, + capitalizeFirstLetter, + turntomins +};