GUI: automatically select URLs from clipboard
[fanfix.git] / src / be / nikiroo / fanfix / supported / E621.java
1 package be.nikiroo.fanfix.supported;
2
3 import java.awt.image.BufferedImage;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.net.URL;
7 import java.util.ArrayList;
8 import java.util.List;
9 import java.util.Map.Entry;
10 import java.util.Scanner;
11
12 import be.nikiroo.fanfix.Instance;
13 import be.nikiroo.fanfix.data.Chapter;
14 import be.nikiroo.fanfix.data.MetaData;
15 import be.nikiroo.fanfix.data.Story;
16 import be.nikiroo.utils.Progress;
17 import be.nikiroo.utils.StringUtils;
18
19 /**
20 * Support class for <a href="http://e621.net/">e621.net</a> and <a
21 * href="http://e926.net/">e926.net</a>, a Furry website supporting comics,
22 * including some of MLP.
23 * <p>
24 * <a href="http://e926.net/">e926.net</a> only shows the "clean" images and
25 * comics, but it can be difficult to browse.
26 *
27 * @author niki
28 */
29 class E621 extends BasicSupport {
30 @Override
31 public String getSourceName() {
32 return "e621.net";
33 }
34
35 @Override
36 protected MetaData getMeta(URL source, InputStream in) throws IOException {
37 MetaData meta = new MetaData();
38
39 meta.setTitle(getTitle(reset(in)));
40 meta.setAuthor(getAuthor(source, reset(in)));
41 meta.setDate("");
42 meta.setTags(new ArrayList<String>()); // TODDO ???
43 meta.setSource(getSourceName());
44 meta.setUrl(source.toString());
45 meta.setPublisher(getSourceName());
46 meta.setUuid(source.toString());
47 meta.setLuid("");
48 meta.setLang("EN");
49 meta.setSubject("Furry");
50 meta.setType(getType().toString());
51 meta.setImageDocument(true);
52 meta.setCover(getCover(source));
53
54 return meta;
55 }
56
57 @Override
58 public Story process(URL url, Progress pg) throws IOException {
59 // There is no chapters on e621, just pagination...
60 Story story = super.process(url, pg);
61
62 Chapter only = new Chapter(1, null);
63 for (Chapter chap : story) {
64 only.getParagraphs().addAll(chap.getParagraphs());
65 }
66
67 story.getChapters().clear();
68 story.getChapters().add(only);
69
70 return story;
71 }
72
73 @Override
74 protected boolean supports(URL url) {
75 String host = url.getHost();
76 if (host.startsWith("www.")) {
77 host = host.substring("www.".length());
78 }
79
80 return ("e621.net".equals(host) || "e926.net".equals(host))
81 && url.getPath().startsWith("/pool/");
82 }
83
84 @Override
85 protected boolean isHtml() {
86 return true;
87 }
88
89 private BufferedImage getCover(URL source) throws IOException {
90 InputStream in = Instance.getCache().open(source, this, true);
91 String images = getChapterContent(new URL(source.toString() + "?page="
92 + 1), in, 1);
93 if (!images.isEmpty()) {
94 int pos = images.indexOf('\n');
95 if (pos >= 0) {
96 images = images.substring(1, pos - 1);
97 return getImage(this, null, images);
98 }
99 }
100
101 return null;
102 }
103
104 private String getAuthor(URL source, InputStream in) throws IOException {
105 String author = getLine(in, "href=\"/post/show/", 0);
106 if (author != null) {
107 String key = "href=\"";
108 int pos = author.indexOf(key);
109 if (pos >= 0) {
110 author = author.substring(pos + key.length());
111 pos = author.indexOf("\"");
112 if (pos >= 0) {
113 author = author.substring(0, pos - 1);
114 String page = source.getProtocol() + "://"
115 + source.getHost() + author;
116 try {
117 InputStream pageIn = Instance.getCache().open(
118 new URL(page), this, false);
119 try {
120 key = "class=\"tag-type-artist\"";
121 author = getLine(pageIn, key, 0);
122 if (author != null) {
123 pos = author.indexOf("<a href=\"");
124 if (pos >= 0) {
125 author = author.substring(pos);
126 pos = author.indexOf("</a>");
127 if (pos >= 0) {
128 author = author.substring(0, pos);
129 return StringUtils.unhtml(author);
130 }
131 }
132 }
133 } finally {
134 pageIn.close();
135 }
136 } catch (Exception e) {
137 // No author found
138 }
139 }
140 }
141 }
142
143 return null;
144 }
145
146 private String getTitle(InputStream in) throws IOException {
147 String title = getLine(in, "<title>", 0);
148 if (title != null) {
149 int pos = title.indexOf('>');
150 if (pos >= 0) {
151 title = title.substring(pos + 1);
152 pos = title.indexOf('<');
153 if (pos >= 0) {
154 title = title.substring(0, pos);
155 }
156 }
157
158 if (title.startsWith("Pool:")) {
159 title = title.substring("Pool:".length());
160 }
161
162 title = StringUtils.unhtml(title).trim();
163 }
164
165 return title;
166 }
167
168 @Override
169 protected String getDesc(URL source, InputStream in) throws IOException {
170 String desc = getLine(in, "margin-bottom: 2em;", 0);
171
172 if (desc != null) {
173 StringBuilder builder = new StringBuilder();
174
175 boolean inTags = false;
176 for (char car : desc.toCharArray()) {
177 if ((inTags && car == '>') || (!inTags && car == '<')) {
178 inTags = !inTags;
179 }
180
181 if (inTags) {
182 builder.append(car);
183 }
184 }
185
186 return builder.toString().trim();
187 }
188
189 return null;
190 }
191
192 @Override
193 protected List<Entry<String, URL>> getChapters(URL source, InputStream in)
194 throws IOException {
195 List<Entry<String, URL>> urls = new ArrayList<Entry<String, URL>>();
196 int last = 1; // no pool/show when only one page
197
198 @SuppressWarnings("resource")
199 Scanner scan = new Scanner(in, "UTF-8");
200 scan.useDelimiter("\\n");
201 while (scan.hasNext()) {
202 String line = scan.next();
203 for (int pos = line.indexOf(source.getPath()); pos >= 0; pos = line
204 .indexOf(source.getPath(), pos + source.getPath().length())) {
205 int equalPos = line.indexOf("=", pos);
206 int quotePos = line.indexOf("\"", pos);
207 if (equalPos >= 0 && quotePos > equalPos) {
208 String snum = line.substring(equalPos + 1, quotePos);
209 try {
210 int num = Integer.parseInt(snum);
211 if (num > last) {
212 last = num;
213 }
214 } catch (NumberFormatException e) {
215 }
216 }
217 }
218 }
219
220 for (int i = 1; i <= last; i++) {
221 final String key = Integer.toString(i);
222 final URL value = new URL(source.toString() + "?page=" + i);
223 urls.add(new Entry<String, URL>() {
224 public URL setValue(URL value) {
225 return null;
226 }
227
228 public URL getValue() {
229 return value;
230 }
231
232 public String getKey() {
233 return key;
234 }
235 });
236 }
237
238 return urls;
239 }
240
241 @Override
242 protected String getChapterContent(URL source, InputStream in, int number)
243 throws IOException {
244 StringBuilder builder = new StringBuilder();
245 String staticSite = "https://static1.e621.net";
246 if (source.getHost().contains("e926")) {
247 staticSite = staticSite.replace("e621", "e926");
248 }
249
250 String key = staticSite + "/data/preview/";
251
252 @SuppressWarnings("resource")
253 Scanner scan = new Scanner(in, "UTF-8");
254 scan.useDelimiter("\\n");
255 while (scan.hasNext()) {
256 String line = scan.next();
257 if (line.contains("class=\"preview")) {
258 for (int pos = line.indexOf(key); pos >= 0; pos = line.indexOf(
259 key, pos + key.length())) {
260 int endPos = line.indexOf("\"", pos);
261 if (endPos >= 0) {
262 String id = line.substring(pos + key.length(), endPos);
263 id = staticSite + "/data/" + id;
264
265 int dotPos = id.lastIndexOf(".");
266 if (dotPos >= 0) {
267 id = id.substring(0, dotPos);
268 builder.append("[");
269 builder.append(id);
270 builder.append("]\n");
271 }
272 }
273 }
274 }
275 }
276
277 return builder.toString();
278 }
279 }