Skip to content

Commit 9004e6b

Browse files
committed
Add utilities to detect and replace broken links.
1 parent 4e1c132 commit 9004e6b

1 file changed

Lines changed: 54 additions & 1 deletion

File tree

application/src/main/java/org/togetherjava/tjbot/features/utils/LinkDetection.java

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
package org.togetherjava.tjbot.features.utils;
22

3+
import java.net.URI;
4+
import java.net.http.HttpClient;
5+
import java.net.http.HttpRequest;
6+
import java.net.http.HttpResponse;
7+
import java.util.concurrent.CompletableFuture;
8+
39
import com.linkedin.urls.Url;
410
import com.linkedin.urls.detection.UrlDetector;
511
import com.linkedin.urls.detection.UrlDetectorOptions;
@@ -57,6 +63,54 @@ public static List<String> extractLinks(String content, Set<LinkFilter> filter)
5763
public static boolean containsLink(String content) {
5864
return !(new UrlDetector(content, UrlDetectorOptions.BRACKET_MATCH).detect().isEmpty());
5965
}
66+
public static CompletableFuture<Boolean> isLinkBroken(String url) {
67+
HttpClient client = HttpClient.newHttpClient();
68+
69+
HttpRequest request = HttpRequest.newBuilder(URI.create(url))
70+
.method("HEAD", HttpRequest.BodyPublishers.noBody())
71+
.build();
72+
73+
return client.sendAsync(request, HttpResponse.BodyHandlers.discarding())
74+
.thenApply(response -> response.statusCode() >= 400)
75+
.exceptionally(ignored -> true);
76+
}
77+
public static CompletableFuture<String> replaceDeadLinks(
78+
String text,
79+
String replacement
80+
) {
81+
Set<LinkFilter> filters = Set.of(
82+
LinkFilter.SUPPRESSED,
83+
LinkFilter.NON_HTTP_SCHEME
84+
);
85+
86+
List<String> links = extractLinks(text, filters);
87+
88+
if (links.isEmpty()) {
89+
return CompletableFuture.completedFuture(text);
90+
}
91+
92+
StringBuilder result = new StringBuilder(text);
93+
94+
List<CompletableFuture<Void>> checks = links.stream()
95+
.map(link ->
96+
isLinkBroken(link).thenAccept(isDead -> {
97+
if (isDead) {
98+
int index = result.indexOf(link);
99+
if (index != -1) {
100+
result.replace(
101+
index,
102+
index + link.length(),
103+
replacement
104+
);
105+
}
106+
}
107+
})
108+
)
109+
.toList();
110+
111+
return CompletableFuture.allOf(checks.toArray(new CompletableFuture[0]))
112+
.thenApply(v -> result.toString());
113+
}
60114

61115
private static Optional<String> toLink(Url url, Set<LinkFilter> filter) {
62116
String raw = url.getOriginalUrl();
@@ -76,7 +130,6 @@ private static Optional<String> toLink(Url url, Set<LinkFilter> filter) {
76130
// Remove trailing punctuation
77131
link = link.substring(0, link.length() - 1);
78132
}
79-
80133
return Optional.of(link);
81134
}
82135

0 commit comments

Comments
 (0)