doc
[nikiroo-utils.git] / supported / Fimfiction.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.MalformedURLException;
7 import java.net.URL;
8 import java.util.ArrayList;
9 import java.util.HashMap;
10 import java.util.List;
11 import java.util.Map;
12 import java.util.Map.Entry;
13 import java.util.Scanner;
14
15 import be.nikiroo.fanfix.Instance;
16 import be.nikiroo.fanfix.data.MetaData;
17 import be.nikiroo.utils.Progress;
18 import be.nikiroo.utils.StringUtils;
19
20 /**
21 * Support class for <a href="http://www.fimfiction.net/">FimFiction.net</a>
22 * stories, a website dedicated to My Little Pony.
23 *
24 * @author niki
25 */
26 class Fimfiction extends BasicSupport {
27 @Override
28 protected boolean isHtml() {
29 return true;
30 }
31
32 @Override
33 public String getSourceName() {
34 return "FimFiction.net";
35 }
36
37 @Override
38 protected MetaData getMeta(URL source, InputStream in) throws IOException {
39 MetaData meta = new MetaData();
40
41 meta.setTitle(getTitle(reset(in)));
42 meta.setAuthor(getAuthor(reset(in)));
43 meta.setDate(getDate(reset(in)));
44 meta.setTags(getTags(reset(in)));
45 meta.setSource(getSourceName());
46 meta.setUrl(source.toString());
47 meta.setPublisher(getSourceName());
48 meta.setUuid(source.toString());
49 meta.setLuid("");
50 meta.setLang("EN");
51 meta.setSubject("MLP");
52 meta.setType(getType().toString());
53 meta.setImageDocument(false);
54 meta.setCover(getCover(reset(in)));
55
56 return meta;
57 }
58
59 @Override
60 public Map<String, String> getCookies() {
61 Map<String, String> cookies = new HashMap<String, String>();
62 cookies.put("view_mature", "true");
63 return cookies;
64 }
65
66 private List<String> getTags(InputStream in) {
67 List<String> tags = new ArrayList<String>();
68 tags.add("MLP");
69
70 @SuppressWarnings("resource")
71 Scanner scan = new Scanner(in, "UTF-8");
72 scan.useDelimiter("\\n");
73 boolean started = false;
74 while (scan.hasNext()) {
75 String line = scan.next();
76
77 if (!started) {
78 started = line.contains("\"story_container\"");
79 }
80
81 if (started && line.contains("class=\"tag-")) {
82 if (line.contains("index.php")) {
83 break; // end of *this story* tags
84 }
85
86 String keyword = "title=\"";
87 Scanner tagScanner = new Scanner(line);
88 tagScanner.useDelimiter(keyword);
89 if (tagScanner.hasNext()) {
90 tagScanner.next();// Ignore first one
91 }
92 while (tagScanner.hasNext()) {
93 String tag = tagScanner.next();
94 if (tag.contains("\"")) {
95 tag = tag.split("\"")[0];
96 tag = StringUtils.unhtml(tag).trim();
97 if (!tag.isEmpty() && !tags.contains(tag)) {
98 tags.add(tag);
99 }
100 }
101 }
102 tagScanner.close();
103 }
104 }
105
106 return tags;
107 }
108
109 private String getTitle(InputStream in) {
110 String line = getLine(in, " property=\"og:title\"", 0);
111 if (line != null) {
112 int pos = -1;
113 for (int i = 0; i < 3; i++) {
114 pos = line.indexOf('"', pos + 1);
115 }
116
117 if (pos >= 0) {
118 line = line.substring(pos + 1);
119 pos = line.indexOf('"');
120 if (pos >= 0) {
121 return StringUtils.unhtml(line.substring(0, pos)).trim();
122 }
123 }
124 }
125
126 return null;
127 }
128
129 private String getAuthor(InputStream in) {
130 String line = getLine(in, " href=\"/user/", 0);
131 if (line != null) {
132 int pos = line.indexOf('"');
133 if (pos >= 0) {
134 line = line.substring(pos + 1);
135 pos = line.indexOf('"');
136 if (pos >= 0) {
137 line = line.substring(0, pos);
138 pos = line.lastIndexOf('/');
139 if (pos >= 0) {
140 line = line.substring(pos + 1);
141 return line.replace('+', ' ');
142 }
143 }
144 }
145 }
146
147 return null;
148 }
149
150 private String getDate(InputStream in) {
151 String line = getLine(in, "<span class=\"date\">", 0);
152 if (line != null) {
153 int pos = -1;
154 for (int i = 0; i < 3; i++) {
155 pos = line.indexOf('>', pos + 1);
156 }
157
158 if (pos >= 0) {
159 line = line.substring(pos + 1);
160 pos = line.indexOf('<');
161 if (pos >= 0) {
162 return line.substring(0, pos).trim();
163 }
164 }
165 }
166
167 return null;
168 }
169
170 @Override
171 protected String getDesc(URL source, InputStream in) {
172 // the og: meta version is the SHORT resume, this is the LONG resume
173 return getLine(in, "class=\"description-text bbcode\"", 1);
174 }
175
176 private BufferedImage getCover(InputStream in) {
177 // Note: the 'og:image' is the SMALL cover, not the full version
178 String cover = getLine(in, "class=\"story_container__story_image\"", 1);
179 if (cover != null) {
180 int pos = cover.indexOf('"');
181 if (pos >= 0) {
182 cover = cover.substring(pos + 1);
183 pos = cover.indexOf('"');
184 if (pos >= 0) {
185 cover = cover.substring(0, pos);
186 }
187 }
188 }
189
190 return getImage(this, null, cover);
191 }
192
193 @Override
194 protected List<Entry<String, URL>> getChapters(URL source, InputStream in,
195 Progress pg) {
196 List<Entry<String, URL>> urls = new ArrayList<Entry<String, URL>>();
197 @SuppressWarnings("resource")
198 Scanner scan = new Scanner(in, "UTF-8");
199 scan.useDelimiter("\\n");
200 boolean started = false;
201 while (scan.hasNext()) {
202 String line = scan.next().trim();
203
204 if (!started) {
205 started = line.equals("<!--Chapters-->");
206 } else {
207 if (line.equals("</form>")) {
208 break;
209 }
210
211 if (line.startsWith("<a href=")
212 || line.contains("class=\"chapter-title\"")) {
213 // Chapter name
214 String name = line;
215 int pos = name.indexOf('>');
216 if (pos >= 0) {
217 name = name.substring(pos + 1);
218 pos = name.indexOf('<');
219 if (pos >= 0) {
220 name = name.substring(0, pos);
221 }
222 }
223 // Chapter content
224 pos = line.indexOf('/');
225 if (pos >= 0) {
226 line = line.substring(pos); // we take the /, not +1
227 pos = line.indexOf('"');
228 if (pos >= 0) {
229 line = line.substring(0, pos);
230 }
231 }
232
233 try {
234 final String key = name;
235 final URL value = new URL("http://www.fimfiction.net"
236 + line);
237 urls.add(new Entry<String, URL>() {
238 @Override
239 public URL setValue(URL value) {
240 return null;
241 }
242
243 @Override
244 public String getKey() {
245 return key;
246 }
247
248 @Override
249 public URL getValue() {
250 return value;
251 }
252 });
253 } catch (MalformedURLException e) {
254 Instance.syserr(e);
255 }
256 }
257 }
258 }
259
260 return urls;
261 }
262
263 @Override
264 protected String getChapterContent(URL source, InputStream in, int number,
265 Progress pg) {
266 return getLine(in, "<div class=\"bbcode\">", 1);
267 }
268
269 @Override
270 protected boolean supports(URL url) {
271 return "fimfiction.net".equals(url.getHost())
272 || "www.fimfiction.net".equals(url.getHost());
273 }
274 }