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