Skip to content

Commit

Permalink
Allow for search in pornhub
Browse files Browse the repository at this point in the history
  • Loading branch information
duncte123 committed Apr 28, 2024
1 parent f1d690d commit becd12e
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 12 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Adding support for the following sources:
- getyarn.io
- Text To Speech (if prefixed with `speak:`)
- TikTok (in beta, works on _most_ videos and **will** break all the time)
- PornHub
- PornHub (search by prefixing with `phsearch:`)
- soundgasm

## Lavalink version compatibility
Expand Down
2 changes: 1 addition & 1 deletion application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ plugins:
getyarn: false # www.getyarn.io
clypit: false # www.clyp.it
tts: false # speak:Words to speak
pornhub: false # should be self-explanatory
pornhub: true # should be self-explanatory
reddit: false # should be self-explanatory
ocremix: true # www.ocremix.org
tiktok: true # tiktok.com
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.dunctebot.sourcemanagers.pornhub;

import com.sedmelluq.discord.lavaplayer.tools.Units;
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo;
import org.jsoup.nodes.Element;

public final class PHHelpers {
public static AudioTrack trackFromSearchElement(Element element, PornHubAudioSourceManager mngr) {
final var info = infoFromSearchElement(element);
return new PornHubAudioTrack(info, mngr);
}

public static AudioTrackInfo infoFromSearchElement(Element element) {
// TODO: parse min:sec duration
// final var durText = element.getElementsByClass("duration").first().text();

// System.out.println(durText);

final String title = element.getElementsByClass("title").first().text();
final String author = element.getElementsByClass("usernameWrap").first().text();
final long duration = Units.CONTENT_LENGTH_UNKNOWN;
final String identifier = element.attr("data-video-vkey");
final String uri = "https://www.pornhub.com/view_video.php?viewkey=" + identifier;
final String imageUrl = element.getElementsByTag("img").first().attr("src");

return new AudioTrackInfo(
title, author, duration, identifier, false, uri, imageUrl, null
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,20 @@
import com.sedmelluq.discord.lavaplayer.tools.FriendlyException;
import com.sedmelluq.discord.lavaplayer.tools.FriendlyException.Severity;
import com.sedmelluq.discord.lavaplayer.tools.JsonBrowser;
import com.sedmelluq.discord.lavaplayer.track.AudioItem;
import com.sedmelluq.discord.lavaplayer.track.AudioReference;
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo;
import com.sedmelluq.discord.lavaplayer.track.*;
import org.apache.commons.io.IOUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.jsoup.Jsoup;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class PornHubAudioSourceManager extends AbstractDuncteBotHttpSource {
private static final String DOMAIN_PATTERN = "https?://([a-z]+\\.)?pornhub\\.(com|net|org)";
Expand All @@ -44,18 +44,21 @@ public class PornHubAudioSourceManager extends AbstractDuncteBotHttpSource {
public static final Pattern VIDEO_INFO_REGEX = Pattern.compile("var flashvars_\\d+ = (\\{.+})");
private static final Pattern MODEL_INFO_REGEX = Pattern.compile("var MODEL_PROFILE = (\\{.+})");

private static final String SEARCH_PREFIX = "phsearch";
private static final String SEARCH_PREFIX_DEFAULT = "phsearch:";

@Override
public String getSourceName() {
return "pornhub";
}

@Override
public AudioItem loadItem(AudioPlayerManager manager, AudioReference reference) {
if (!VIDEO_REGEX.matcher(reference.identifier).matches()) {
return null;
}

try {
if (!VIDEO_REGEX.matcher(reference.identifier).matches()) {
return processAsSearchQuery(reference);
}

return loadItemOnce(reference);
} catch (Exception e) {
throw ExceptionTools.wrapUnfriendlyExceptions("Something went wrong", Severity.SUSPICIOUS, e);
Expand All @@ -77,6 +80,56 @@ public AudioTrack decodeTrack(AudioTrackInfo trackInfo, DataInput input) {
return new PornHubAudioTrack(trackInfo, this);
}

private AudioItem processAsSearchQuery(AudioReference reference) throws IOException {
if (reference.identifier.startsWith(SEARCH_PREFIX)) {
if (reference.identifier.startsWith(SEARCH_PREFIX_DEFAULT)) {
return attemptSearch(reference.identifier.substring(SEARCH_PREFIX_DEFAULT.length()).trim());
}
}

return null;
}

public AudioItem attemptSearch(String query) throws IOException {
// https://www.pornhub.com/video/search?search=a+few+words

final String html = loadHtml(
"https://www.pornhub.com/video/search?search=" +
URLEncoder.encode(query, StandardCharsets.UTF_8)
);

if (html == null) {
notAvailable();
}

// ul#videoSearchResult -> contains results
// li.pcVideoListItem -> contains all videos

final var document = Jsoup.parse(html);
final var results = document.select("ul#videoSearchResult").first();

if (results == null) {
throw new FriendlyException(
"Search result element not found, contact dev",
Severity.SUSPICIOUS,
new IllegalArgumentException("Search result element not found, contact dev")
);
}

final var videos = results.select("li.pcVideoListItem");

final var phTracks = videos.stream()
.map((it) -> PHHelpers.trackFromSearchElement(it, this))
.collect(Collectors.toList());

return new BasicAudioPlaylist(
"Search results for " + query,
phTracks,
null,
true
);
}

private AudioItem loadItemOnce(AudioReference reference) throws IOException {
final String html = loadHtml(reference.identifier);

Expand Down Expand Up @@ -163,7 +216,7 @@ private JsonBrowser getModelInfo(String html) throws IOException {
private String loadHtml(String url) throws IOException {
final HttpGet httpGet = new HttpGet(url);

httpGet.setHeader("Cookie", "platform=pc; age_verified=1");
httpGet.setHeader("Cookie", "platform=pc; age_verified=1; accessAgeDisclaimerPH=1");

try (final CloseableHttpResponse response = getHttpInterface().execute(httpGet)) {
final int statusCode = response.getStatusLine().getStatusCode();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ private String parseJsValueToUrl(String htmlPage, String js) {
private String loadMp4Url(String jsonPage, String cookie) throws IOException {
final HttpGet mediaGet = new HttpGet(jsonPage);

mediaGet.setHeader("Cookie", cookie + "; platform=pc; age_verified=1");
mediaGet.setHeader("Cookie", cookie + "; platform=pc; age_verified=1; accessAgeDisclaimerPH=1");
mediaGet.setHeader("Referer", getPlayerPage(this.trackInfo.identifier));

try (final CloseableHttpResponse response = this.getSourceManager().getHttpInterface().execute(mediaGet)) {
Expand Down
31 changes: 31 additions & 0 deletions source-managers/src/test/java/PHSearchTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright 2022 Duncan "duncte123" Sterken
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import com.dunctebot.sourcemanagers.pornhub.PornHubAudioSourceManager;
import com.dunctebot.sourcemanagers.pornhub.PornHubAudioTrack;
import com.sedmelluq.discord.lavaplayer.track.AudioReference;

public class PHSearchTest {
public static void main(String[] args) throws Exception {
// final var link = "https://www.pornhub.com/view_video.php?viewkey=ph5fc5ef73cfc87";
final var link = "https://www.pornhub.com/view_video.php?viewkey=ph6383940fcb8d7";
final var mngr = new PornHubAudioSourceManager();

final var test = mngr.attemptSearch("minecraft bedwards");

System.out.println(test);
}
}

0 comments on commit becd12e

Please sign in to comment.