Skip to content

Commit 53b08ee

Browse files
committed
moved server stuff to its own class
improved exception throw created general connection function for cleaner api requests improved documentation
1 parent 463a0da commit 53b08ee

File tree

5 files changed

+120
-125
lines changed

5 files changed

+120
-125
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
### Notes:
22

33
- Brings DeArrow to RSS
4-
- Works with invidious and youtube feeds
4+
- Works with invidious and YouTube feeds
55
- not tested in actual feed reader
66

77
### How?
@@ -14,3 +14,5 @@
1414

1515
- write tests
1616
- create frontend?
17+
- add insecure mode where you don't request the image and check for a valid return but just pass the url without
18+
checking

src/main/java/de/mueller/franz/DeArrow.java

Lines changed: 35 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -5,45 +5,38 @@
55
import java.io.BufferedReader;
66
import java.io.IOException;
77
import java.io.InputStreamReader;
8-
import java.net.HttpURLConnection;
9-
import java.net.URL;
10-
import java.net.URLEncoder;
8+
import java.net.*;
9+
import java.nio.charset.StandardCharsets;
1110
import java.util.List;
1211

13-
// TODO Javadoc
14-
12+
/**
13+
* class responsible for all things with the DeArrow api and data formatting
14+
*/
1515
public class DeArrow {
1616

1717
/**
1818
* get DeArrow information
1919
*
20-
* @param videoID
20+
* @param videoID id of the individual video
2121
* @return response as String
2222
* @throws IOException
2323
*/
2424
public String getInitialInformation(String videoID) throws IOException {
2525
String apiUrl = "https://sponsor.ajay.app/api/branding";
2626

2727
// Encode the videoID parameter
28-
String encodedVideoID = URLEncoder.encode(videoID, "UTF-8");
28+
String encodedVideoID = URLEncoder.encode(videoID, StandardCharsets.UTF_8);
2929

3030
// Construct the URL with query parameters
3131
String queryParameters = String.format("?videoID=%s", encodedVideoID);
3232
String completeUrl = apiUrl + queryParameters;
3333

34-
URL url = new URL(completeUrl);
35-
HttpURLConnection con = (HttpURLConnection) url.openConnection();
34+
// connect to api and return response if successful
35+
HttpURLConnection con = initializeConnection(completeUrl);
36+
if (con == null) return null;
3637

37-
// TODO move to Config / separate Object
38-
con.setRequestMethod("GET");
39-
con.setRequestProperty("Content-Type", "application/json");
40-
con.setRequestProperty("Accept", "application/json");
41-
// handle everything that's not 200
42-
if (con.getResponseCode() != HttpURLConnection.HTTP_OK) {
43-
return null;
44-
}
4538
try (BufferedReader br = new BufferedReader(
46-
new InputStreamReader(con.getInputStream(), "utf-8"))) {
39+
new InputStreamReader(con.getInputStream(), StandardCharsets.UTF_8))) {
4740
StringBuilder response = new StringBuilder();
4841
String responseLine;
4942
while ((responseLine = br.readLine()) != null) {
@@ -57,25 +50,17 @@ public String getInitialInformation(String videoID) throws IOException {
5750
* helper class representing the extracted information
5851
*/
5952
public static class ProcessedInformation {
60-
private String title;
61-
private String url;
53+
private final String title;
54+
private final String url;
6255

6356
public String getTitle() {
6457
return title;
6558
}
6659

67-
public void setTitle(String title) {
68-
this.title = title;
69-
}
70-
7160
public String getUrl() {
7261
return url;
7362
}
7463

75-
public void setUrl(String url) {
76-
this.url = url;
77-
}
78-
7964
public ProcessedInformation(String title, String url) {
8065
this.title = title;
8166
this.url = url;
@@ -85,7 +70,7 @@ public ProcessedInformation(String title, String url) {
8570
/**
8671
* post process information from DeArrow api
8772
*
88-
* @param jsonResponse
73+
* @param jsonResponse api response from DeArrow
8974
* @return title and url as ProcessedInformation (null if not existing)
9075
*/
9176
public ProcessedInformation processInformation(String videoID, String jsonResponse) throws IOException {
@@ -125,11 +110,12 @@ public ProcessedInformation processInformation(String videoID, String jsonRespon
125110
}
126111
return new ProcessedInformation(title, url);
127112
}
113+
128114
/**
129115
* fetches thumbnail image
130116
*
131-
* @param videoID
132-
* @param number
117+
* @param videoID id of video in question
118+
* @param number Thumbnail timestamp (DeArrow internal number)
133119
* @return image url or null
134120
* @throws IOException
135121
*/
@@ -138,31 +124,32 @@ public String getImageInformation(String videoID, double number) throws IOExcept
138124
String apiUrl = "https://dearrow-thumb.ajay.app/api/v1/getThumbnail";
139125

140126
// Encode the videoID parameter
141-
String encodedVideoID = URLEncoder.encode(videoID, "UTF-8");
127+
String encodedVideoID = URLEncoder.encode(videoID, StandardCharsets.UTF_8);
142128

143129
// Construct the URL with query parameters
144130
String queryParameters = String.format("?videoID=%s&time=%s", encodedVideoID, number);
145131
String completeUrl = apiUrl + queryParameters;
146-
132+
// get api response and return complete url if successful
133+
HttpURLConnection con = initializeConnection(completeUrl);
134+
if (con == null) return null;
135+
else return completeUrl;
136+
}
137+
/**
138+
* create GET connection to provided url with json as request/ response
139+
* @param completeUrl url you want to connect to (please encode UTF-8)
140+
* @return connection ready to go or null if connection is not ok
141+
* @throws IOException
142+
*/
143+
private HttpURLConnection initializeConnection(String completeUrl) throws IOException {
147144
URL url = new URL(completeUrl);
148145
HttpURLConnection con = (HttpURLConnection) url.openConnection();
149146
con.setRequestMethod("GET");
150147
con.setRequestProperty("Content-Type", "application/json");
151148
con.setRequestProperty("Accept", "application/json");
152-
153-
int responseCode = con.getResponseCode();
154-
if (responseCode == HttpURLConnection.HTTP_OK) {
155-
return completeUrl;
156-
} else return null;
157-
158-
// no need for receiving and process the image
159-
/*try (BufferedReader br = new BufferedReader(
160-
new InputStreamReader(con.getInputStream(), "utf-8"))) {
161-
StringBuilder response = new StringBuilder();
162-
String responseLine;
163-
while ((responseLine = br.readLine()) != null) {
164-
response.append(responseLine.trim());
165-
}
166-
}*/
149+
// handle everything that's not 200
150+
if (con.getResponseCode() != HttpURLConnection.HTTP_OK) {
151+
return null;
152+
}
153+
return con;
167154
}
168155
}

src/main/java/de/mueller/franz/HandleRssFeed.java

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@
1919
import java.net.URL;
2020
import java.util.List;
2121

22-
// TODO Javadoc
23-
22+
/**
23+
* class responsible to do everything RSS feed related
24+
*/
2425
public class HandleRssFeed {
2526
DeArrow deArrow = new DeArrow();
2627

@@ -31,16 +32,14 @@ public class HandleRssFeed {
3132
* @return SyndFeed
3233
* @throws IOException
3334
* @throws FeedException
35+
* @throws FeedException
3436
*/
3537
public SyndFeed readFeed(String feedUrl) {
3638
try {
3739
URL url = new URI(feedUrl).toURL();
3840
return new SyndFeedInput().build(new XmlReader(url));
3941
} catch (Exception e) {
40-
e.printStackTrace();
41-
System.out.println("ERROR: " + e.getMessage());
42-
// TODO throw new Exception("Wrong feed ...: " + e.stackTrace());
43-
throw new IllegalArgumentException("Wrong feed provided. Please provide a valid YouTube RSS feed");
42+
throw new IllegalArgumentException("Wrong feed provided. Please provide a valid YouTube RSS feed: " + e.getMessage());
4443
}
4544
}
4645

@@ -76,7 +75,7 @@ public void writeFeedToFile(SyndFeed feed) throws IOException, FeedException {
7675
/**
7776
* read feed from file
7877
*
79-
* @param fileName
78+
* @param fileName name of the file or path if not in root folder
8079
* @return SyndFeed
8180
* @throws IOException
8281
* @throws FeedException
@@ -85,16 +84,16 @@ public SyndFeed readFeedFromFile(String fileName) throws IOException, FeedExcept
8584
return this.readFeed(new FileReader(fileName));
8685
}
8786

88-
public SyndFeed readFeed(Reader content) throws IOException, FeedException {
87+
public SyndFeed readFeed(Reader content) throws FeedException {
8988
SyndFeedInput input = new SyndFeedInput();
9089
return input.build(content);
9190
}
9291

9392
/**
9493
* replace url for media:thumbnail element with jdom2
9594
*
96-
* @param entry
97-
* @param newUrl
95+
* @param entry entry which is changed
96+
* @param newUrl image url you want to change it to
9897
*/
9998
public void setMediaThumbnailUrl(SyndEntry entry, String newUrl) {
10099
// yt and invidious
@@ -123,7 +122,7 @@ public void setMediaThumbnailUrl(SyndEntry entry, String newUrl) {
123122
/**
124123
* get url for media:thumbnail element with jdom2
125124
*
126-
* @param entry
125+
* @param entry entry which is edited
127126
* @return url from media:thumbnail
128127
*/
129128
public String getMediaThumbnailUrl(SyndEntry entry) {
@@ -142,23 +141,22 @@ public String getMediaThumbnailUrl(SyndEntry entry) {
142141
/**
143142
* create the final feed from url
144143
*
145-
* @param rssFeedURL
144+
* @param rssFeedURL url to the YouTube/ Invidious RSS feed you want to DeArrow
146145
* @throws FeedException
147146
* @throws IOException
148147
*/
149148
public String createModifiedFeed(String rssFeedURL) throws FeedException, IOException {
150149
SyndFeed feed = readFeed(rssFeedURL);
151150
for (SyndEntry entry : feed.getEntries()) {
152-
// get vidID from entry
153-
// TODO Example: url.../...=...:... ->
154-
String videoId = entry.getUri().substring(entry.getUri().lastIndexOf('=') + 1); // TODO why?
155-
videoId = videoId.substring(videoId.lastIndexOf(":") + 1); // TODO why?
156-
// get info
151+
// get vidID from entry by formatting the uri ("yt:video:7DKv5H5Frt0" --> "7DKv5H5Frt0")
152+
String videoId = entry.getUri();
153+
videoId = videoId.substring(videoId.lastIndexOf(":") + 1);
154+
// get information (title and thumbnail url)
157155
DeArrow.ProcessedInformation processedInformation = deArrow.processInformation(videoId, deArrow.getInitialInformation(videoId));
158156
// change rss feed
159157
editEntry(entry, processedInformation.getTitle(), processedInformation.getUrl());
160158
}
161-
// create file
159+
// create file if wanted
162160
// writeFeedToFile(feed);
163161

164162
// return as String
Lines changed: 9 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,16 @@
11
package de.mueller.franz;
22

3-
import spark.Spark;
4-
5-
import static spark.Spark.*;
6-
73
public class Main {
8-
// TODO main -> Server
94
public static void main(String[] args) {
10-
// DeArrow: https://wiki.sponsor.ajay.app/w/API_Docs/DeArrow
11-
// ROME: https://rometools.github.io/rome/
12-
// Spark: https://sparkjava.com/
13-
14-
// ToDo make dynamic and exposed to web; speed up image request; write tests
15-
HandleRssFeed handleRssFeed = new HandleRssFeed();
16-
// Tom Scott
17-
// String rssFeedURL = "https://www.youtube.com/feeds/videos.xml?channel_id=UCBa659QWEk1AI4Tg--mrJ2A";
18-
String rssFeedURL = "https://yewtu.be/feed/channel/UCBa659QWEk1AI4Tg--mrJ2A";
19-
// Franz3
20-
// String rssFeedURL = "https://yewtu.be/feed/channel/UCBa659QWEk1AI4Tg--mrJ2A";
21-
22-
Spark.webSocketIdleTimeoutMillis((60 * 1000) * 5);
23-
// initialize web server for http://localhost:4567/DeArrow/
24-
get("/DeArrow/*", (request, response) -> {
25-
// get the inputted YouTube/ Invidious url
26-
String feedUrl = request.raw().getRequestURL().toString();
27-
String queryString = request.raw().getQueryString();
28-
if (queryString != null) {
29-
feedUrl += "?" + queryString;
30-
}
31-
feedUrl = feedUrl.replace("http://localhost:4567/DeArrow/", "");
32-
feedUrl = feedUrl.replace("http://localhost:4567/dearrow/", "");
33-
// respond
34-
response.type("text/xml");
35-
return handleRssFeed.createModifiedFeed(feedUrl);
5+
Server server = new Server();
6+
// Test URLs:
7+
// Tom Scott:
8+
// https://www.youtube.com/feeds/videos.xml?channel_id=UCBa659QWEk1AI4Tg--mrJ2A
9+
// https://yewtu.be/feed/channel/UCBa659QWEk1AI4Tg--mrJ2A
10+
// Franz3:
11+
// https://yewtu.be/feed/channel/UCBa659QWEk1AI4Tg--mrJ2A
3612

37-
});
38-
// handle internal error (500)
39-
internalServerError((request, response) -> {
40-
response.type("text/html");
41-
return "<html>" +
42-
"<body>" +
43-
"<img src=\"https://http.cat/500\" alt=\"https://http.cat/500\" width=\"747\" height=\"598\">" +
44-
"</body>" +
45-
"</html>";
46-
});
47-
// handle wrong address (404)
48-
notFound((request, response) -> {
49-
response.type("text/html");
50-
return "<html>" +
51-
"<body>" +
52-
"<img src=\"https://http.cat/404\" alt=\"https://http.cat/404\" width=\"747\" height=\"598\">" +
53-
"</body>" +
54-
"</html>";
55-
});
56-
// handle IllegalArgumentException (thrown when url is wrong)
57-
get("/wrong_url", (request, response) -> {
58-
response.type("text/html");
59-
return "Please provide a valid feed url";
60-
});
61-
exception(IllegalArgumentException.class, (exception, request, response) -> {
62-
response.redirect("/wrong_url");
63-
});
13+
// start server
14+
server.startWebserver();
6415
}
6516
}

0 commit comments

Comments
 (0)