mirror of https://github.com/kurisufriend/Clover
parent
08df656d05
commit
ede3e69f5c
@ -0,0 +1,12 @@ |
||||
package org.floens.chan.core.site.common; |
||||
|
||||
|
||||
import android.util.JsonReader; |
||||
|
||||
public interface ChanReader { |
||||
void loadThread(JsonReader reader, ChanReaderProcessingQueue queue) throws Exception; |
||||
|
||||
void loadCatalog(JsonReader reader, ChanReaderProcessingQueue queue) throws Exception; |
||||
|
||||
void readPostObject(JsonReader reader, ChanReaderProcessingQueue queue) throws Exception; |
||||
} |
@ -0,0 +1,63 @@ |
||||
package org.floens.chan.core.site.common; |
||||
|
||||
|
||||
import android.annotation.SuppressLint; |
||||
|
||||
import org.floens.chan.core.model.Post; |
||||
import org.floens.chan.core.model.orm.Loadable; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
class ChanReaderProcessingQueue { |
||||
@SuppressLint("UseSparseArrays") |
||||
private Map<Integer, Post> cachedByNo = new HashMap<>(); |
||||
private Loadable loadable; |
||||
|
||||
private List<Post> toReuse = new ArrayList<>(); |
||||
private List<Post.Builder> toParse = new ArrayList<>(); |
||||
private Post.Builder op; |
||||
|
||||
public ChanReaderProcessingQueue(List<Post> toReuse, Loadable loadable) { |
||||
this.loadable = loadable; |
||||
|
||||
for (int i = 0; i < toReuse.size(); i++) { |
||||
Post cache = toReuse.get(i); |
||||
cachedByNo.put(cache.no, cache); |
||||
} |
||||
} |
||||
|
||||
public Post getCachedPost(int no) { |
||||
return cachedByNo.get(no); |
||||
} |
||||
|
||||
public void addForReuse(Post post) { |
||||
toReuse.add(post); |
||||
} |
||||
|
||||
public void addForParse(Post.Builder postBuilder) { |
||||
toParse.add(postBuilder); |
||||
} |
||||
|
||||
public void setOp(Post.Builder op) { |
||||
this.op = op; |
||||
} |
||||
|
||||
public Loadable getLoadable() { |
||||
return loadable; |
||||
} |
||||
|
||||
List<Post> getToReuse() { |
||||
return toReuse; |
||||
} |
||||
|
||||
List<Post.Builder> getToParse() { |
||||
return toParse; |
||||
} |
||||
|
||||
Post.Builder getOp() { |
||||
return op; |
||||
} |
||||
} |
@ -0,0 +1,242 @@ |
||||
package org.floens.chan.core.site.common; |
||||
|
||||
|
||||
import android.util.JsonReader; |
||||
|
||||
import org.floens.chan.core.model.Post; |
||||
import org.floens.chan.core.model.PostHttpIcon; |
||||
import org.floens.chan.core.model.PostImage; |
||||
import org.floens.chan.core.site.SiteEndpoints; |
||||
import org.jsoup.parser.Parser; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
import okhttp3.HttpUrl; |
||||
|
||||
public class FutabaChanReader implements ChanReader { |
||||
@Override |
||||
public void loadThread(JsonReader reader, ChanReaderProcessingQueue queue) throws Exception { |
||||
reader.beginObject(); |
||||
// Page object
|
||||
while (reader.hasNext()) { |
||||
String key = reader.nextName(); |
||||
if (key.equals("posts")) { |
||||
reader.beginArray(); |
||||
// Thread array
|
||||
while (reader.hasNext()) { |
||||
// Thread object
|
||||
readPostObject(reader, queue); |
||||
} |
||||
reader.endArray(); |
||||
} else { |
||||
reader.skipValue(); |
||||
} |
||||
} |
||||
reader.endObject(); |
||||
} |
||||
|
||||
@Override |
||||
public void loadCatalog(JsonReader reader, ChanReaderProcessingQueue queue) throws Exception { |
||||
reader.beginArray(); // Array of pages
|
||||
|
||||
while (reader.hasNext()) { |
||||
reader.beginObject(); // Page object
|
||||
|
||||
while (reader.hasNext()) { |
||||
if (reader.nextName().equals("threads")) { |
||||
reader.beginArray(); // Threads array
|
||||
|
||||
while (reader.hasNext()) { |
||||
readPostObject(reader, queue); |
||||
} |
||||
|
||||
reader.endArray(); |
||||
} else { |
||||
reader.skipValue(); |
||||
} |
||||
} |
||||
|
||||
reader.endObject(); |
||||
} |
||||
|
||||
reader.endArray(); |
||||
} |
||||
|
||||
@Override |
||||
public void readPostObject(JsonReader reader, ChanReaderProcessingQueue queue) throws Exception { |
||||
Post.Builder builder = new Post.Builder(); |
||||
builder.board(queue.getLoadable().board); |
||||
|
||||
// File
|
||||
String fileId = null; |
||||
String fileExt = null; |
||||
int fileWidth = 0; |
||||
int fileHeight = 0; |
||||
long fileSize = 0; |
||||
boolean fileSpoiler = false; |
||||
String fileName = null; |
||||
|
||||
// Country flag
|
||||
String countryCode = null; |
||||
String trollCountryCode = null; |
||||
String countryName = null; |
||||
|
||||
// 4chan pass leaf
|
||||
int since4pass = 0; |
||||
|
||||
reader.beginObject(); |
||||
while (reader.hasNext()) { |
||||
String key = reader.nextName(); |
||||
|
||||
switch (key) { |
||||
case "no": |
||||
builder.id(reader.nextInt()); |
||||
break; |
||||
/*case "now": |
||||
post.date = reader.nextString(); |
||||
break;*/ |
||||
case "sub": |
||||
builder.subject(reader.nextString()); |
||||
break; |
||||
case "name": |
||||
builder.name(reader.nextString()); |
||||
break; |
||||
case "com": |
||||
builder.comment(reader.nextString()); |
||||
break; |
||||
case "tim": |
||||
fileId = reader.nextString(); |
||||
break; |
||||
case "time": |
||||
builder.setUnixTimestampSeconds(reader.nextLong()); |
||||
break; |
||||
case "ext": |
||||
fileExt = reader.nextString().replace(".", ""); |
||||
break; |
||||
case "w": |
||||
fileWidth = reader.nextInt(); |
||||
break; |
||||
case "h": |
||||
fileHeight = reader.nextInt(); |
||||
break; |
||||
case "fsize": |
||||
fileSize = reader.nextLong(); |
||||
break; |
||||
case "filename": |
||||
fileName = reader.nextString(); |
||||
break; |
||||
case "trip": |
||||
builder.tripcode(reader.nextString()); |
||||
break; |
||||
case "country": |
||||
countryCode = reader.nextString(); |
||||
break; |
||||
case "troll_country": |
||||
trollCountryCode = reader.nextString(); |
||||
break; |
||||
case "country_name": |
||||
countryName = reader.nextString(); |
||||
break; |
||||
case "spoiler": |
||||
fileSpoiler = reader.nextInt() == 1; |
||||
break; |
||||
case "resto": |
||||
int opId = reader.nextInt(); |
||||
builder.op(opId == 0); |
||||
builder.opId(opId); |
||||
break; |
||||
case "sticky": |
||||
builder.sticky(reader.nextInt() == 1); |
||||
break; |
||||
case "closed": |
||||
builder.closed(reader.nextInt() == 1); |
||||
break; |
||||
case "archived": |
||||
builder.archived(reader.nextInt() == 1); |
||||
break; |
||||
case "replies": |
||||
builder.replies(reader.nextInt()); |
||||
break; |
||||
case "images": |
||||
builder.images(reader.nextInt()); |
||||
break; |
||||
case "unique_ips": |
||||
builder.uniqueIps(reader.nextInt()); |
||||
break; |
||||
case "id": |
||||
builder.posterId(reader.nextString()); |
||||
break; |
||||
case "capcode": |
||||
builder.moderatorCapcode(reader.nextString()); |
||||
break; |
||||
case "since4pass": |
||||
since4pass = reader.nextInt(); |
||||
break; |
||||
default: |
||||
// Unknown/ignored key
|
||||
reader.skipValue(); |
||||
break; |
||||
} |
||||
} |
||||
reader.endObject(); |
||||
|
||||
if (builder.op) { |
||||
// Update OP fields later on the main thread
|
||||
Post.Builder op = new Post.Builder(); |
||||
op.closed(builder.closed); |
||||
op.archived(builder.archived); |
||||
op.sticky(builder.sticky); |
||||
op.replies(builder.replies); |
||||
op.images(builder.images); |
||||
op.uniqueIps(builder.uniqueIps); |
||||
queue.setOp(op); |
||||
} |
||||
|
||||
Post cached = queue.getCachedPost(builder.id); |
||||
if (cached != null) { |
||||
// Id is known, use the cached post object.
|
||||
queue.addForReuse(cached); |
||||
return; |
||||
} |
||||
|
||||
SiteEndpoints endpoints = queue.getLoadable().getSite().endpoints(); |
||||
if (fileId != null && fileName != null && fileExt != null) { |
||||
Map<String, String> hack = new HashMap<>(2); |
||||
hack.put("tim", fileId); |
||||
hack.put("ext", fileExt); |
||||
builder.image(new PostImage.Builder() |
||||
.originalName(String.valueOf(fileId)) |
||||
.thumbnailUrl(endpoints.thumbnailUrl(builder, fileSpoiler, hack)) |
||||
.imageUrl(endpoints.imageUrl(builder, hack)) |
||||
.filename(Parser.unescapeEntities(fileName, false)) |
||||
.extension(fileExt) |
||||
.imageWidth(fileWidth) |
||||
.imageHeight(fileHeight) |
||||
.spoiler(fileSpoiler) |
||||
.size(fileSize) |
||||
.build()); |
||||
} |
||||
|
||||
if (countryCode != null && countryName != null) { |
||||
Map<String, String> arg = new HashMap<>(1); |
||||
arg.put("country_code", countryCode); |
||||
HttpUrl countryUrl = endpoints.icon(builder, "country", arg); |
||||
builder.addHttpIcon(new PostHttpIcon(countryUrl, countryName)); |
||||
} |
||||
|
||||
if (trollCountryCode != null && countryName != null) { |
||||
Map<String, String> arg = new HashMap<>(1); |
||||
arg.put("troll_country_code", trollCountryCode); |
||||
HttpUrl countryUrl = endpoints.icon(builder, "troll_country", arg); |
||||
builder.addHttpIcon(new PostHttpIcon(countryUrl, countryName)); |
||||
} |
||||
|
||||
if (since4pass != 0) { |
||||
HttpUrl iconUrl = endpoints.icon(builder, "since4pass", null); |
||||
builder.addHttpIcon(new PostHttpIcon(iconUrl, String.valueOf(since4pass))); |
||||
} |
||||
|
||||
queue.addForParse(builder); |
||||
} |
||||
} |
Loading…
Reference in new issue