├── .gitignore
├── .idea
├── .name
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── encodings.xml
├── gradle.xml
├── misc.xml
├── modules.xml
└── runConfigurations.xml
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── codevate
│ │ └── mvvmreddit
│ │ └── ApplicationTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── codevate
│ │ │ └── mvvmreddit
│ │ │ ├── MvvmRedditApplication.java
│ │ │ ├── client
│ │ │ └── RedditClient.java
│ │ │ ├── dependencyinjection
│ │ │ ├── ApplicationComponent.java
│ │ │ └── module
│ │ │ │ ├── ApplicationModule.java
│ │ │ │ └── ClientModule.java
│ │ │ ├── deserializer
│ │ │ ├── RedditDateDeserializer.java
│ │ │ └── RedditObjectJsonDeserializer.java
│ │ │ ├── model
│ │ │ ├── RedditComment.java
│ │ │ ├── RedditLink.java
│ │ │ ├── RedditListing.java
│ │ │ └── RedditObject.java
│ │ │ ├── view
│ │ │ ├── FeedActivity.java
│ │ │ ├── PostAdapter.java
│ │ │ └── PostViewHolder.java
│ │ │ └── viewmodel
│ │ │ ├── FeedViewModel.java
│ │ │ └── PostViewModel.java
│ └── res
│ │ ├── layout
│ │ ├── action_progress.xml
│ │ ├── activity_feed.xml
│ │ └── view_item_post.xml
│ │ ├── menu
│ │ └── feed.xml
│ │ ├── mipmap-hdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ └── ic_launcher.png
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ ├── java
│ └── com
│ │ └── codevate
│ │ └── mvvmreddit
│ │ └── viewmodel
│ │ └── FeedViewModelTest.java
│ └── resources
│ ├── top.json
│ └── top2.json
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── images
├── screenshot.png
└── screenshot_full.png
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | MVVM Reddit
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
23 |
24 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # mvvm-reddit
2 |
3 | Example of MVVM architecture on Android, using RxJava.
4 |
5 | 
6 |
7 | ### About Codevate
8 | Codevate is a specialist [UK mobile app development company](https://www.codevate.com/) that builds cloud-connected software. This repository was created for a blog post about [mobile application development](https://www.codevate.com/services/mobile-app-development) and was written by David Bennett.
9 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'com.neenbedankt.android-apt'
3 | apply plugin: 'me.tatarka.retrolambda'
4 |
5 | android {
6 | compileSdkVersion 23
7 | buildToolsVersion "23.0.3"
8 |
9 | defaultConfig {
10 | applicationId "com.codevate.mvvmreddit"
11 | minSdkVersion 16
12 | targetSdkVersion 23
13 | versionCode 1
14 | versionName "1.0"
15 | }
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | compileOptions {
23 | sourceCompatibility JavaVersion.VERSION_1_8
24 | targetCompatibility JavaVersion.VERSION_1_8
25 | }
26 | }
27 |
28 | dependencies {
29 | compile fileTree(dir: 'libs', include: ['*.jar'])
30 | testCompile 'junit:junit:4.12'
31 | testCompile 'org.mockito:mockito-core:1.10.19'
32 | compile 'com.android.support:appcompat-v7:23.4.0'
33 | compile 'com.android.support:support-v4:23.2.1'
34 | compile 'com.android.support:design:23.2.1'
35 | compile 'com.android.support:recyclerview-v7:23.2.1'
36 | compile 'com.android.support:cardview-v7:23.2.1'
37 | compile 'com.google.dagger:dagger:2.4'
38 | compile 'com.squareup.picasso:picasso:2.5.2'
39 | compile 'com.squareup.retrofit2:retrofit:2.1.0'
40 | compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
41 | compile 'com.squareup.retrofit2:converter-gson:2.1.0'
42 | compile 'com.squareup.okhttp3:logging-interceptor:3.3.1'
43 | compile 'io.reactivex:rxjava:1.1.8'
44 | compile 'io.reactivex:rxandroid:1.2.1'
45 | compile 'org.ocpsoft.prettytime:prettytime:4.0.1.Final'
46 | compile "org.androidannotations:androidannotations-api:4.0.0"
47 | compile group: 'commons-io', name: 'commons-io', version: '2.5'
48 | compile group: 'commons-validator', name: 'commons-validator', version: '1.5.1'
49 | apt "org.androidannotations:androidannotations:4.0.0"
50 | apt 'com.google.dagger:dagger-compiler:2.4'
51 | apt 'org.projectlombok:lombok:1.16.8'
52 | provided 'org.projectlombok:lombok:1.16.8'
53 | }
54 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Applications/adt-bundle/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/codevate/mvvmreddit/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.codevate.mvvmreddit;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | public class ApplicationTest extends ApplicationTestCase
7 | {
8 | public ApplicationTest()
9 | {
10 | super(Application.class);
11 | }
12 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codevate/mvvmreddit/MvvmRedditApplication.java:
--------------------------------------------------------------------------------
1 | package com.codevate.mvvmreddit;
2 |
3 | import android.app.Application;
4 |
5 | import com.codevate.mvvmreddit.dependencyinjection.ApplicationComponent;
6 | import com.codevate.mvvmreddit.dependencyinjection.DaggerApplicationComponent;
7 | import com.codevate.mvvmreddit.dependencyinjection.module.ApplicationModule;
8 |
9 | import org.androidannotations.annotations.EApplication;
10 |
11 | @EApplication
12 | public class MvvmRedditApplication extends Application
13 | {
14 | private ApplicationComponent applicationComponent;
15 |
16 | @Override
17 | public void onCreate()
18 | {
19 | super.onCreate();
20 |
21 | applicationComponent = DaggerApplicationComponent
22 | .builder()
23 | .applicationModule(new ApplicationModule(this))
24 | .build();
25 | }
26 |
27 | public ApplicationComponent component()
28 | {
29 | return applicationComponent;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codevate/mvvmreddit/client/RedditClient.java:
--------------------------------------------------------------------------------
1 | package com.codevate.mvvmreddit.client;
2 |
3 | import com.codevate.mvvmreddit.model.RedditObject;
4 |
5 | import retrofit2.http.GET;
6 | import retrofit2.http.Query;
7 | import rx.Observable;
8 |
9 | public interface RedditClient
10 | {
11 | @GET("/top.json")
12 | Observable getTop(@Query("after") String after, @Query("limit") int limit);
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codevate/mvvmreddit/dependencyinjection/ApplicationComponent.java:
--------------------------------------------------------------------------------
1 | package com.codevate.mvvmreddit.dependencyinjection;
2 |
3 | import com.codevate.mvvmreddit.dependencyinjection.module.ApplicationModule;
4 | import com.codevate.mvvmreddit.dependencyinjection.module.ClientModule;
5 | import com.codevate.mvvmreddit.view.FeedActivity;
6 |
7 | import javax.inject.Singleton;
8 |
9 | import dagger.Component;
10 |
11 | @Singleton
12 | @Component(modules = {ApplicationModule.class, ClientModule.class})
13 | public interface ApplicationComponent
14 | {
15 | void inject(FeedActivity activity);
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codevate/mvvmreddit/dependencyinjection/module/ApplicationModule.java:
--------------------------------------------------------------------------------
1 | package com.codevate.mvvmreddit.dependencyinjection.module;
2 |
3 | import com.codevate.mvvmreddit.MvvmRedditApplication;
4 |
5 | import dagger.Module;
6 |
7 | @Module
8 | public class ApplicationModule
9 | {
10 | private MvvmRedditApplication application;
11 |
12 | public ApplicationModule(MvvmRedditApplication application)
13 | {
14 | this.application = application;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codevate/mvvmreddit/dependencyinjection/module/ClientModule.java:
--------------------------------------------------------------------------------
1 | package com.codevate.mvvmreddit.dependencyinjection.module;
2 |
3 | import com.codevate.mvvmreddit.BuildConfig;
4 | import com.codevate.mvvmreddit.client.RedditClient;
5 | import com.codevate.mvvmreddit.model.RedditObject;
6 | import com.codevate.mvvmreddit.deserializer.RedditObjectJsonDeserializer;
7 | import com.codevate.mvvmreddit.deserializer.RedditDateDeserializer;
8 | import com.google.gson.FieldNamingPolicy;
9 | import com.google.gson.Gson;
10 | import com.google.gson.GsonBuilder;
11 |
12 | import java.util.Date;
13 |
14 | import dagger.Module;
15 | import dagger.Provides;
16 | import okhttp3.OkHttpClient;
17 | import okhttp3.logging.HttpLoggingInterceptor;
18 | import retrofit2.Retrofit;
19 | import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
20 | import retrofit2.converter.gson.GsonConverterFactory;
21 | import rx.schedulers.Schedulers;
22 |
23 | @Module
24 | public class ClientModule
25 | {
26 | @Provides
27 | public RedditClient provideRedditClient()
28 | {
29 | Gson gson = new GsonBuilder()
30 | .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
31 | .registerTypeAdapter(RedditObject.class, new RedditObjectJsonDeserializer())
32 | .registerTypeAdapter(Date.class, new RedditDateDeserializer())
33 | .create();
34 |
35 | RxJavaCallAdapterFactory rxAdapter = RxJavaCallAdapterFactory.createWithScheduler(Schedulers.io());
36 |
37 | HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
38 | interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
39 | OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
40 | if (BuildConfig.DEBUG)
41 | {
42 | okHttpClientBuilder.addInterceptor(interceptor);
43 | }
44 | OkHttpClient client = okHttpClientBuilder.build();
45 |
46 | Retrofit retrofit = new Retrofit.Builder()
47 | .baseUrl("http://reddit.com")
48 | .client(client)
49 | .addConverterFactory(GsonConverterFactory.create(gson))
50 | .addCallAdapterFactory(rxAdapter)
51 | .build();
52 |
53 | return retrofit.create(RedditClient.class);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codevate/mvvmreddit/deserializer/RedditDateDeserializer.java:
--------------------------------------------------------------------------------
1 | package com.codevate.mvvmreddit.deserializer;
2 |
3 | import com.google.gson.JsonDeserializationContext;
4 | import com.google.gson.JsonDeserializer;
5 | import com.google.gson.JsonElement;
6 | import com.google.gson.JsonParseException;
7 |
8 | import java.lang.reflect.Type;
9 | import java.util.Date;
10 |
11 | /**
12 | * Reddit uses timestamps for dates. This deserializer transforms them into Java dates;
13 | */
14 | public class RedditDateDeserializer implements JsonDeserializer
15 | {
16 | @Override
17 | public Object deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
18 | {
19 | return new Date(json.getAsJsonPrimitive().getAsLong() * 1000);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codevate/mvvmreddit/deserializer/RedditObjectJsonDeserializer.java:
--------------------------------------------------------------------------------
1 | package com.codevate.mvvmreddit.deserializer;
2 |
3 | import android.util.Log;
4 |
5 | import com.codevate.mvvmreddit.model.RedditComment;
6 | import com.codevate.mvvmreddit.model.RedditLink;
7 | import com.codevate.mvvmreddit.model.RedditListing;
8 | import com.codevate.mvvmreddit.model.RedditObject;
9 | import com.google.gson.JsonDeserializationContext;
10 | import com.google.gson.JsonDeserializer;
11 | import com.google.gson.JsonElement;
12 | import com.google.gson.JsonObject;
13 | import com.google.gson.JsonParseException;
14 |
15 | import java.lang.reflect.Type;
16 |
17 | /**
18 | * Deserialize the Reddit object into a subclass based on its 'kind' field.
19 | */
20 | public class RedditObjectJsonDeserializer implements JsonDeserializer
21 | {
22 | private static String TAG = "RedditObjectJsonDeserializer";
23 |
24 | @Override
25 | public RedditObject deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
26 | {
27 | if (json == null || !json.isJsonObject())
28 | {
29 | return null;
30 | }
31 |
32 | try
33 | {
34 | JsonObject jsonObject = json.getAsJsonObject();
35 | String kind = jsonObject.get("kind").getAsString();
36 |
37 | return context.deserialize(jsonObject.get("data"), getClassForKind(kind));
38 | }
39 | catch (JsonParseException e)
40 | {
41 | Log.e(TAG, String.format("Could not deserialize Reddit element: %s", json.toString()));
42 | return null;
43 | }
44 | }
45 |
46 | private Class getClassForKind(String kind)
47 | {
48 | switch (kind)
49 | {
50 | case "Listing":
51 | return RedditListing.class;
52 | case "t1":
53 | return RedditComment.class;
54 | case "t3":
55 | return RedditLink.class;
56 | default:
57 | Log.e(TAG, String.format("Unsupported Reddit kind: %s", kind));
58 | return null;
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codevate/mvvmreddit/model/RedditComment.java:
--------------------------------------------------------------------------------
1 | package com.codevate.mvvmreddit.model;
2 |
3 | import java.util.Date;
4 |
5 | import lombok.Data;
6 | import lombok.EqualsAndHashCode;
7 |
8 | @Data
9 | public class RedditComment implements RedditObject
10 | {
11 | private String id;
12 | private String body;
13 | private String bodyHtml;
14 | private String author;
15 | private String subredditId;
16 | private String linkId;
17 | private String parentId;
18 | private String score;
19 | private String ups;
20 | private String downs;
21 | private Date created;
22 | private Date createdUtc;
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codevate/mvvmreddit/model/RedditLink.java:
--------------------------------------------------------------------------------
1 | package com.codevate.mvvmreddit.model;
2 |
3 | import java.util.Date;
4 |
5 | import lombok.Data;
6 | import lombok.EqualsAndHashCode;
7 |
8 | @Data
9 | public class RedditLink implements RedditObject
10 | {
11 | private String id;
12 | private String title;
13 | private String domain;
14 | private String subreddit;
15 | private String subredditId;
16 | private String linkFlairText;
17 | private String author;
18 | private String thumbnail;
19 | private String permalink;
20 | private String url;
21 | private int score;
22 | private int ups;
23 | private int downs;
24 | private int numComments;
25 | private boolean over18;
26 | private boolean hideScore;
27 | private Date created;
28 | private Date createdUtc;
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codevate/mvvmreddit/model/RedditListing.java:
--------------------------------------------------------------------------------
1 | package com.codevate.mvvmreddit.model;
2 |
3 | import java.util.List;
4 |
5 | import lombok.Data;
6 | import lombok.EqualsAndHashCode;
7 |
8 | @Data
9 | public class RedditListing implements RedditObject
10 | {
11 | private List children;
12 | private String before;
13 | private String after;
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codevate/mvvmreddit/model/RedditObject.java:
--------------------------------------------------------------------------------
1 | package com.codevate.mvvmreddit.model;
2 |
3 | public interface RedditObject
4 | {
5 | }
6 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codevate/mvvmreddit/view/FeedActivity.java:
--------------------------------------------------------------------------------
1 | package com.codevate.mvvmreddit.view;
2 |
3 | import android.support.v7.app.AppCompatActivity;
4 | import android.os.Bundle;
5 | import android.support.v7.widget.LinearLayoutManager;
6 | import android.support.v7.widget.RecyclerView;
7 | import android.view.MenuItem;
8 |
9 | import com.codevate.mvvmreddit.MvvmRedditApplication;
10 | import com.codevate.mvvmreddit.R;
11 | import com.codevate.mvvmreddit.viewmodel.FeedViewModel;
12 |
13 | import org.androidannotations.annotations.AfterViews;
14 | import org.androidannotations.annotations.EActivity;
15 | import org.androidannotations.annotations.OptionsMenu;
16 | import org.androidannotations.annotations.OptionsMenuItem;
17 | import org.androidannotations.annotations.ViewById;
18 |
19 | import javax.inject.Inject;
20 |
21 | import rx.Observable;
22 | import rx.android.schedulers.AndroidSchedulers;
23 | import rx.subscriptions.CompositeSubscription;
24 |
25 | @EActivity(R.layout.activity_feed)
26 | @OptionsMenu(R.menu.feed)
27 | public class FeedActivity extends AppCompatActivity
28 | {
29 | @ViewById(R.id.post_list)
30 | RecyclerView postList;
31 |
32 | @OptionsMenuItem(R.id.progress)
33 | MenuItem loadingMenuItem;
34 |
35 | @Inject
36 | FeedViewModel viewModel;
37 |
38 | private PostAdapter postAdapter;
39 | private LinearLayoutManager postListLayoutManager;
40 |
41 | /** Hold active loading observable subscriptions, so that they can be unsubscribed from when the activity is destroyed */
42 | private CompositeSubscription subscriptions;
43 |
44 | @Override
45 | protected void onCreate(Bundle savedInstanceState)
46 | {
47 | super.onCreate(savedInstanceState);
48 |
49 | ((MvvmRedditApplication) getApplication()).component().inject(this);
50 |
51 | subscriptions = new CompositeSubscription();
52 | }
53 |
54 | @Override
55 | protected void onDestroy()
56 | {
57 | super.onDestroy();
58 |
59 | subscriptions.unsubscribe();
60 | }
61 |
62 | @AfterViews
63 | void init()
64 | {
65 | initViews();
66 | initBindings();
67 |
68 | // Initial page load
69 | loadNextPage();
70 | }
71 |
72 | private void initViews()
73 | {
74 | postListLayoutManager = new LinearLayoutManager(this);
75 | postList.setLayoutManager(postListLayoutManager);
76 |
77 | postAdapter = new PostAdapter();
78 | postList.setAdapter(postAdapter);
79 | }
80 |
81 | private void initBindings()
82 | {
83 | // Observable that emits when the RecyclerView is scrolled to the bottom
84 | Observable infiniteScrollObservable = Observable.create(subscriber -> {
85 | postList.addOnScrollListener(new RecyclerView.OnScrollListener()
86 | {
87 | @Override
88 | public void onScrolled(RecyclerView recyclerView, int dx, int dy)
89 | {
90 | int totalItemCount = postListLayoutManager.getItemCount();
91 | int visibleItemCount = postListLayoutManager.getChildCount();
92 | int firstVisibleItem = postListLayoutManager.findFirstVisibleItemPosition();
93 |
94 | if ((visibleItemCount + firstVisibleItem) >= totalItemCount)
95 | {
96 | subscriber.onNext(null);
97 | }
98 | }
99 | });
100 | });
101 |
102 | subscriptions.addAll(
103 | // Bind list of posts to the RecyclerView
104 | viewModel.postsObservable().observeOn(AndroidSchedulers.mainThread()).subscribe(postAdapter::setItems),
105 |
106 | // Bind loading status to show/hide loading spinner
107 | viewModel.isLoadingObservable().observeOn(AndroidSchedulers.mainThread()).subscribe(this::setIsLoading),
108 |
109 | // Trigger next page load when RecyclerView is scrolled to the bottom
110 | infiniteScrollObservable.subscribe(x -> loadNextPage())
111 | );
112 | }
113 |
114 | private void loadNextPage()
115 | {
116 | subscriptions.add(
117 | viewModel.loadMorePosts().subscribe()
118 | );
119 | }
120 |
121 | private void setIsLoading(boolean isLoading)
122 | {
123 | if (loadingMenuItem != null)
124 | {
125 | loadingMenuItem.setVisible(isLoading);
126 | }
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codevate/mvvmreddit/view/PostAdapter.java:
--------------------------------------------------------------------------------
1 | package com.codevate.mvvmreddit.view;
2 |
3 | import android.support.v7.widget.RecyclerView;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 |
8 | import com.codevate.mvvmreddit.R;
9 | import com.codevate.mvvmreddit.viewmodel.PostViewModel;
10 |
11 | import java.util.ArrayList;
12 | import java.util.List;
13 |
14 | public class PostAdapter extends RecyclerView.Adapter
15 | {
16 | private List items = new ArrayList<>();
17 |
18 | public PostAdapter()
19 | {
20 | setHasStableIds(true);
21 | }
22 |
23 | @Override
24 | public PostViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
25 | {
26 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_item_post, parent, false);
27 | return new PostViewHolder(view);
28 | }
29 |
30 | @Override
31 | public void onBindViewHolder(PostViewHolder holder, int position)
32 | {
33 | holder.bind(getItem(position));
34 | }
35 |
36 | @Override
37 | public int getItemCount()
38 | {
39 | return items.size();
40 | }
41 |
42 | @Override
43 | public long getItemId(int position)
44 | {
45 | return getItem(position).getId().hashCode();
46 | }
47 |
48 | public PostViewModel getItem(int position)
49 | {
50 | return items.get(position);
51 | }
52 |
53 | public void setItems(List items)
54 | {
55 | if (items == null)
56 | {
57 | return;
58 | }
59 |
60 | this.items = new ArrayList<>(items);
61 | notifyDataSetChanged();
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codevate/mvvmreddit/view/PostViewHolder.java:
--------------------------------------------------------------------------------
1 | package com.codevate.mvvmreddit.view;
2 |
3 | import android.support.v7.widget.RecyclerView;
4 | import android.view.View;
5 | import android.widget.ImageView;
6 | import android.widget.TextView;
7 |
8 | import com.codevate.mvvmreddit.R;
9 | import com.codevate.mvvmreddit.viewmodel.PostViewModel;
10 | import com.squareup.picasso.Picasso;
11 |
12 | import org.apache.commons.validator.routines.UrlValidator;
13 |
14 | public class PostViewHolder extends RecyclerView.ViewHolder
15 | {
16 | private View view;
17 | private TextView titleTextView;
18 | private TextView subtitleTextView;
19 | private TextView subtitle2TextView;
20 | private ImageView thumbnailImageView;
21 |
22 | public PostViewHolder(View view)
23 | {
24 | super(view);
25 |
26 | this.view = view;
27 | this.titleTextView = (TextView) view.findViewById(R.id.title);
28 | this.subtitleTextView = (TextView) view.findViewById(R.id.subtitle);
29 | this.subtitle2TextView = (TextView) view.findViewById(R.id.subtitle2);
30 | this.thumbnailImageView = (ImageView)view.findViewById(R.id.thumbnail);
31 | }
32 |
33 | public void bind(PostViewModel viewModel)
34 | {
35 | titleTextView.setText(viewModel.getTitle());
36 | subtitleTextView.setText(String.format("%s - %s - %s (%s)", viewModel.getAuthor(), viewModel.getCreatedOn(), viewModel.getSubreddit(), viewModel.getDomain()));
37 | subtitle2TextView.setText(String.format("%d points - %d comments", viewModel.getScore(), viewModel.getNumComments()));
38 |
39 | UrlValidator urlValidator = new UrlValidator();
40 | boolean hasThumbnail = viewModel.getThumbnailUrl() != null && urlValidator.isValid(viewModel.getThumbnailUrl());
41 |
42 | // Show/hide the thumbnail if there is/isn't one
43 | thumbnailImageView.setVisibility(hasThumbnail ? View.VISIBLE : View.GONE);
44 |
45 | // Load the thumbnail if there is one
46 | if (hasThumbnail)
47 | {
48 | Picasso.with(view.getContext()).load(viewModel.getThumbnailUrl()).into(thumbnailImageView);
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codevate/mvvmreddit/viewmodel/FeedViewModel.java:
--------------------------------------------------------------------------------
1 | package com.codevate.mvvmreddit.viewmodel;
2 |
3 | import com.codevate.mvvmreddit.client.RedditClient;
4 | import com.codevate.mvvmreddit.model.RedditLink;
5 | import com.codevate.mvvmreddit.model.RedditListing;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | import javax.inject.Inject;
11 |
12 | import rx.Observable;
13 | import rx.subjects.BehaviorSubject;
14 |
15 | public class FeedViewModel
16 | {
17 | private RedditClient redditClient;
18 |
19 | private int pageLimit;
20 | private String afterToken;
21 | private BehaviorSubject> postSubject = BehaviorSubject.create(new ArrayList<>());
22 | private BehaviorSubject isLoadingSubject = BehaviorSubject.create(false);
23 |
24 | @Inject
25 | public FeedViewModel(RedditClient redditClient)
26 | {
27 | this.redditClient = redditClient;
28 | this.pageLimit = 25;
29 | }
30 |
31 | public Observable> loadMorePosts()
32 | {
33 | // Don't try and load if we're already loading
34 | if (isLoadingSubject.getValue())
35 | {
36 | return Observable.empty();
37 | }
38 |
39 | isLoadingSubject.onNext(true);
40 |
41 | return redditClient
42 | .getTop(afterToken, pageLimit)
43 | // Safe to cast to RedditListing, as this is always returned from top posts
44 | .cast(RedditListing.class)
45 | // Store the after token, so we can use it to get the next page of posts is a subsequent load
46 | .doOnNext(listing -> afterToken = listing.getAfter())
47 | // Flatten into observable of RedditLinks
48 | .map(RedditListing::getChildren)
49 | .flatMapIterable(list -> list)
50 | .filter(object -> object instanceof RedditLink)
51 | // Transform model to viewmodel
52 | .map(link -> new PostViewModel((RedditLink) link))
53 | // Merge viewmodels into a single list to be emitted
54 | .toList()
55 | // Concatenate the new posts to the current posts list, then emit it via the post subject
56 | .doOnNext(list -> {
57 | List fullList = new ArrayList<>(postSubject.getValue());
58 | fullList.addAll(list);
59 | postSubject.onNext(fullList);
60 | })
61 | .doOnTerminate(() -> isLoadingSubject.onNext(false));
62 | }
63 |
64 | public Observable> postsObservable()
65 | {
66 | return postSubject.asObservable();
67 | }
68 |
69 | public Observable isLoadingObservable()
70 | {
71 | return isLoadingSubject.asObservable();
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/app/src/main/java/com/codevate/mvvmreddit/viewmodel/PostViewModel.java:
--------------------------------------------------------------------------------
1 | package com.codevate.mvvmreddit.viewmodel;
2 |
3 | import com.codevate.mvvmreddit.model.RedditLink;
4 |
5 | import org.ocpsoft.prettytime.PrettyTime;
6 |
7 | import lombok.Data;
8 |
9 | @Data
10 | public class PostViewModel
11 | {
12 | private String id;
13 | private String title;
14 | private String author;
15 | private String thumbnailUrl;
16 | private String createdOn;
17 | private String subreddit;
18 | private String domain;
19 | private int numComments;
20 | private int score;
21 |
22 | public PostViewModel(RedditLink redditLink)
23 | {
24 | this.id = redditLink.getId();
25 | this.title = redditLink.getTitle();
26 | this.author = redditLink.getAuthor();
27 | this.thumbnailUrl = redditLink.getThumbnail();
28 | this.subreddit = redditLink.getSubreddit();
29 | this.domain = redditLink.getDomain();
30 | this.numComments = redditLink.getNumComments();
31 | this.score = redditLink.getScore();
32 |
33 | PrettyTime pt = new PrettyTime();
34 | this.createdOn = pt.format(redditLink.getCreated());
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/action_progress.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_feed.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/view_item_post.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
21 |
22 |
26 |
27 |
34 |
35 |
42 |
43 |
48 |
49 |
54 |
55 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/feed.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codevate/mvvm-reddit/f6d4d1a525370dbe6bd66eca0ab2c493777e3a68/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codevate/mvvm-reddit/f6d4d1a525370dbe6bd66eca0ab2c493777e3a68/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codevate/mvvm-reddit/f6d4d1a525370dbe6bd66eca0ab2c493777e3a68/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codevate/mvvm-reddit/f6d4d1a525370dbe6bd66eca0ab2c493777e3a68/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codevate/mvvm-reddit/f6d4d1a525370dbe6bd66eca0ab2c493777e3a68/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #31AD98
4 | #057F6B
5 | #82DCCD
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | MVVM Reddit
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/test/java/com/codevate/mvvmreddit/viewmodel/FeedViewModelTest.java:
--------------------------------------------------------------------------------
1 | package com.codevate.mvvmreddit.viewmodel;
2 |
3 | import com.codevate.mvvmreddit.client.RedditClient;
4 | import com.codevate.mvvmreddit.deserializer.RedditDateDeserializer;
5 | import com.codevate.mvvmreddit.deserializer.RedditObjectJsonDeserializer;
6 | import com.codevate.mvvmreddit.model.RedditObject;
7 | import com.google.gson.FieldNamingPolicy;
8 | import com.google.gson.Gson;
9 | import com.google.gson.GsonBuilder;
10 |
11 | import org.apache.commons.io.IOUtils;
12 | import org.junit.Before;
13 | import org.junit.Test;
14 | import org.junit.runner.RunWith;
15 | import org.mockito.Mock;
16 | import org.mockito.runners.MockitoJUnitRunner;
17 |
18 | import java.util.Date;
19 | import java.util.List;
20 |
21 | import rx.Observable;
22 | import rx.observers.TestSubscriber;
23 |
24 | import static org.mockito.Matchers.anyInt;
25 | import static org.mockito.Matchers.anyString;
26 | import static org.mockito.Mockito.times;
27 | import static org.mockito.Mockito.verify;
28 | import static org.mockito.Mockito.when;
29 |
30 | @RunWith(MockitoJUnitRunner.class)
31 | public class FeedViewModelTest
32 | {
33 | @Mock
34 | RedditClient redditClient;
35 |
36 | private Gson gson;
37 |
38 | @Before
39 | public void setup() throws Exception
40 | {
41 | gson = new GsonBuilder()
42 | .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
43 | .registerTypeAdapter(RedditObject.class, new RedditObjectJsonDeserializer())
44 | .registerTypeAdapter(Date.class, new RedditDateDeserializer())
45 | .create();
46 |
47 | when(redditClient.getTop(null, 25)).thenReturn(Observable.just(topPage1()));
48 | when(redditClient.getTop("t3_4tsqgv", 25)).thenReturn(Observable.just(topPage2()));
49 | }
50 |
51 | @Test
52 | public void loadNextPage_loadsPage1() throws Exception
53 | {
54 | FeedViewModel viewModel = new FeedViewModel(redditClient);
55 |
56 | TestSubscriber> testSubscriber = new TestSubscriber<>();
57 | viewModel.loadMorePosts().subscribe(testSubscriber);
58 | testSubscriber.assertCompleted();
59 | testSubscriber.assertValueCount(1);
60 |
61 | verify(redditClient, times(1)).getTop(anyString(), anyInt());
62 | verify(redditClient).getTop(null, 25);
63 | }
64 |
65 | @Test
66 | public void loadNextPage_loadsPage2() throws Exception
67 | {
68 | FeedViewModel viewModel = new FeedViewModel(redditClient);
69 |
70 | // Load initial page
71 | TestSubscriber> testSubscriber = new TestSubscriber<>();
72 | viewModel.loadMorePosts().subscribe(testSubscriber);
73 | testSubscriber.assertCompleted();
74 | testSubscriber.assertValueCount(1);
75 |
76 | verify(redditClient).getTop(null, 25);
77 | verify(redditClient, times(1)).getTop(null, 25);
78 |
79 | // Load next page
80 | testSubscriber = new TestSubscriber<>();
81 | viewModel.loadMorePosts().subscribe(testSubscriber);
82 | testSubscriber.assertCompleted();
83 | testSubscriber.assertValueCount(1);
84 |
85 | verify(redditClient, times(2)).getTop(anyString(), anyInt());
86 | verify(redditClient, times(1)).getTop("t3_4tsqgv", 25);
87 | verify(redditClient).getTop("t3_4tsqgv", 25);
88 | }
89 |
90 | @Test
91 | public void isLoading_toggled() throws Exception
92 | {
93 | FeedViewModel viewModel = new FeedViewModel(redditClient);
94 |
95 | // Initial state - not loading
96 | TestSubscriber testSubscriber = new TestSubscriber<>();
97 | viewModel.isLoadingObservable().subscribe(testSubscriber);
98 | testSubscriber.assertValue(false);
99 |
100 | // Start loading page
101 | Observable> postsObservable = viewModel.loadMorePosts();
102 |
103 | testSubscriber = new TestSubscriber<>();
104 | viewModel.isLoadingObservable().subscribe(testSubscriber);
105 | testSubscriber.assertValue(true);
106 |
107 | // Finish loading page
108 | postsObservable.subscribe();
109 |
110 | testSubscriber = new TestSubscriber<>();
111 | viewModel.isLoadingObservable().subscribe(testSubscriber);
112 | testSubscriber.assertValue(false);
113 | }
114 |
115 | private RedditObject topPage1() throws Exception
116 | {
117 | return gson.fromJson(IOUtils.toString(getClass().getResourceAsStream("/top.json")), RedditObject.class);
118 | }
119 |
120 | private RedditObject topPage2() throws Exception
121 | {
122 | return gson.fromJson(IOUtils.toString(getClass().getResourceAsStream("/top.json")), RedditObject.class);
123 | }
124 | }
--------------------------------------------------------------------------------
/app/src/test/resources/top2.json:
--------------------------------------------------------------------------------
1 | {
2 | "kind": "Listing",
3 | "data": {
4 | "modhash": "06u3o2s4axdf025f37115c07d227d61d03e1d0c8cc501d9866",
5 | "children": [
6 | {
7 | "kind": "t3",
8 | "data": {
9 | "domain": "asiancorrespondent.com",
10 | "banned_by": null,
11 | "media_embed": {},
12 | "subreddit": "worldnews",
13 | "selftext_html": null,
14 | "selftext": "",
15 | "likes": null,
16 | "suggested_sort": null,
17 | "user_reports": [],
18 | "secure_media": null,
19 | "link_flair_text": null,
20 | "id": "4sj7q2",
21 | "from_kind": null,
22 | "gilded": 0,
23 | "archived": false,
24 | "clicked": false,
25 | "report_reasons": null,
26 | "author": "randomnamegendarme",
27 | "media": null,
28 | "score": 7175,
29 | "approved_by": null,
30 | "over_18": false,
31 | "hidden": false,
32 | "num_comments": 9896,
33 | "thumbnail": "",
34 | "subreddit_id": "t5_2qh13",
35 | "hide_score": false,
36 | "edited": false,
37 | "link_flair_css_class": null,
38 | "author_flair_css_class": null,
39 | "downs": 0,
40 | "secure_media_embed": {},
41 | "saved": false,
42 | "removal_reason": null,
43 | "stickied": false,
44 | "from": null,
45 | "is_self": false,
46 | "from_id": null,
47 | "permalink": "/r/worldnews/comments/4sj7q2/body_count_rises_as_new_philippines_president/",
48 | "locked": false,
49 | "name": "t3_4sj7q2",
50 | "created": 1468384442,
51 | "url": "https://asiancorrespondent.com/2016/07/philippines-duterte-drug-addicts/",
52 | "author_flair_text": null,
53 | "quarantine": false,
54 | "title": "Body count rises as new Philippines president calls for drug addicts to be killed",
55 | "created_utc": 1468355642,
56 | "distinguished": null,
57 | "mod_reports": [],
58 | "visited": false,
59 | "num_reports": null,
60 | "ups": 7175
61 | }
62 | },
63 | {
64 | "kind": "t3",
65 | "data": {
66 | "domain": "i.imgur.com",
67 | "banned_by": null,
68 | "media_embed": {},
69 | "subreddit": "funny",
70 | "selftext_html": null,
71 | "selftext": "",
72 | "likes": null,
73 | "suggested_sort": null,
74 | "user_reports": [],
75 | "secure_media": null,
76 | "link_flair_text": null,
77 | "id": "4vq7rj",
78 | "from_kind": null,
79 | "gilded": 6,
80 | "archived": false,
81 | "clicked": false,
82 | "report_reasons": null,
83 | "author": "Nephelus",
84 | "media": null,
85 | "score": 8096,
86 | "approved_by": null,
87 | "over_18": false,
88 | "hidden": false,
89 | "preview": {
90 | "images": [
91 | {
92 | "source": {
93 | "url": "https://i.redditmedia.com/ZGLiI_3CZMmqinFSPeW0VG4p-_qKVNxCHKQrTHPWjyE.jpg?s=bfd51aa282f61c64b7552818a52679d3",
94 | "width": 1400,
95 | "height": 790
96 | },
97 | "resolutions": [
98 | {
99 | "url": "https://i.redditmedia.com/ZGLiI_3CZMmqinFSPeW0VG4p-_qKVNxCHKQrTHPWjyE.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=108&s=a29739def4885c76a6a0f0ad5b77c9fb",
100 | "width": 108,
101 | "height": 60
102 | },
103 | {
104 | "url": "https://i.redditmedia.com/ZGLiI_3CZMmqinFSPeW0VG4p-_qKVNxCHKQrTHPWjyE.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=216&s=ce67f0c1b49eb86c5296a60281028f69",
105 | "width": 216,
106 | "height": 121
107 | },
108 | {
109 | "url": "https://i.redditmedia.com/ZGLiI_3CZMmqinFSPeW0VG4p-_qKVNxCHKQrTHPWjyE.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=320&s=d520caed31665d4f9ef1cd24c31a81f6",
110 | "width": 320,
111 | "height": 180
112 | },
113 | {
114 | "url": "https://i.redditmedia.com/ZGLiI_3CZMmqinFSPeW0VG4p-_qKVNxCHKQrTHPWjyE.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=640&s=a4627f48e7f9c7610b740e5dfc73ff5e",
115 | "width": 640,
116 | "height": 361
117 | },
118 | {
119 | "url": "https://i.redditmedia.com/ZGLiI_3CZMmqinFSPeW0VG4p-_qKVNxCHKQrTHPWjyE.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=960&s=122562e287c8d6dd080320e2275fcbeb",
120 | "width": 960,
121 | "height": 541
122 | },
123 | {
124 | "url": "https://i.redditmedia.com/ZGLiI_3CZMmqinFSPeW0VG4p-_qKVNxCHKQrTHPWjyE.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=1080&s=4764666dff20e081a6073c8fedab7651",
125 | "width": 1080,
126 | "height": 609
127 | }
128 | ],
129 | "variants": {},
130 | "id": "gIoDTuK3S5JFDCZDtbA0IWW0hJ1vXmr3Opf5mABb4hg"
131 | }
132 | ]
133 | },
134 | "num_comments": 1596,
135 | "thumbnail": "http://b.thumbs.redditmedia.com/1fX47ot3K3a7RV8VmmQhkrpURUweWgaJ6831eN--XUg.jpg",
136 | "subreddit_id": "t5_2qh33",
137 | "hide_score": false,
138 | "edited": false,
139 | "link_flair_css_class": null,
140 | "author_flair_css_class": null,
141 | "downs": 0,
142 | "secure_media_embed": {},
143 | "saved": false,
144 | "removal_reason": null,
145 | "post_hint": "image",
146 | "stickied": false,
147 | "from": null,
148 | "is_self": false,
149 | "from_id": null,
150 | "permalink": "/r/funny/comments/4vq7rj/due_to_all_the_health_hazards_surrounding_the_rio/",
151 | "locked": false,
152 | "name": "t3_4vq7rj",
153 | "created": 1470132973,
154 | "url": "http://i.imgur.com/FApqk3D.jpg",
155 | "author_flair_text": null,
156 | "quarantine": false,
157 | "title": "Due to all the health hazards surrounding the Rio Olympics, I figured they could use a new logo. [OC]",
158 | "created_utc": 1470104173,
159 | "distinguished": null,
160 | "mod_reports": [],
161 | "visited": false,
162 | "num_reports": null,
163 | "ups": 8096
164 | }
165 | },
166 | {
167 | "kind": "t3",
168 | "data": {
169 | "domain": "good.is",
170 | "banned_by": null,
171 | "media_embed": {},
172 | "subreddit": "worldnews",
173 | "selftext_html": null,
174 | "selftext": "",
175 | "likes": null,
176 | "suggested_sort": null,
177 | "user_reports": [],
178 | "secure_media": null,
179 | "link_flair_text": null,
180 | "id": "4s7cd1",
181 | "from_kind": null,
182 | "gilded": 0,
183 | "archived": false,
184 | "clicked": false,
185 | "report_reasons": null,
186 | "author": "anutensil",
187 | "media": null,
188 | "score": 7127,
189 | "approved_by": null,
190 | "over_18": false,
191 | "hidden": false,
192 | "num_comments": 1868,
193 | "thumbnail": "",
194 | "subreddit_id": "t5_2qh13",
195 | "hide_score": false,
196 | "edited": false,
197 | "link_flair_css_class": null,
198 | "author_flair_css_class": null,
199 | "downs": 0,
200 | "secure_media_embed": {},
201 | "saved": false,
202 | "removal_reason": null,
203 | "stickied": false,
204 | "from": null,
205 | "is_self": false,
206 | "from_id": null,
207 | "permalink": "/r/worldnews/comments/4s7cd1/eating_endangered_species_is_now_illegal_in_china/",
208 | "locked": false,
209 | "name": "t3_4s7cd1",
210 | "created": 1468213068,
211 | "url": "https://www.good.is/articles/no-more-endangered-species-for-dinner",
212 | "author_flair_text": null,
213 | "quarantine": false,
214 | "title": "Eating Endangered Species Is Now Illegal In China",
215 | "created_utc": 1468184268,
216 | "distinguished": null,
217 | "mod_reports": [],
218 | "visited": false,
219 | "num_reports": null,
220 | "ups": 7127
221 | }
222 | },
223 | {
224 | "kind": "t3",
225 | "data": {
226 | "domain": "en.wikipedia.org",
227 | "banned_by": null,
228 | "media_embed": {},
229 | "subreddit": "todayilearned",
230 | "selftext_html": null,
231 | "selftext": "",
232 | "likes": null,
233 | "suggested_sort": null,
234 | "user_reports": [],
235 | "secure_media": null,
236 | "link_flair_text": null,
237 | "id": "4uj9ea",
238 | "from_kind": null,
239 | "gilded": 0,
240 | "archived": false,
241 | "clicked": false,
242 | "report_reasons": null,
243 | "author": "I-am-theEggman",
244 | "media": null,
245 | "score": 7102,
246 | "approved_by": null,
247 | "over_18": false,
248 | "hidden": false,
249 | "num_comments": 1063,
250 | "thumbnail": "default",
251 | "subreddit_id": "t5_2qqjc",
252 | "hide_score": false,
253 | "edited": false,
254 | "link_flair_css_class": null,
255 | "author_flair_css_class": null,
256 | "downs": 0,
257 | "secure_media_embed": {},
258 | "saved": false,
259 | "removal_reason": null,
260 | "stickied": false,
261 | "from": null,
262 | "is_self": false,
263 | "from_id": null,
264 | "permalink": "/r/todayilearned/comments/4uj9ea/til_in_1898_nikola_tesla_once_tricked_an_entire/",
265 | "locked": false,
266 | "name": "t3_4uj9ea",
267 | "created": 1469490551,
268 | "url": "https://en.wikipedia.org/wiki/Radio_control#cite_note-1",
269 | "author_flair_text": null,
270 | "quarantine": false,
271 | "title": "TIL In 1898 Nikola Tesla once tricked an entire crowd into believing they could control a toy boat by shouting commands - he had in fact invented Radio Control and was piloting the boat himself.",
272 | "created_utc": 1469461751,
273 | "distinguished": null,
274 | "mod_reports": [],
275 | "visited": false,
276 | "num_reports": null,
277 | "ups": 7102
278 | }
279 | },
280 | {
281 | "kind": "t3",
282 | "data": {
283 | "domain": "imgur.com",
284 | "banned_by": null,
285 | "media_embed": {},
286 | "subreddit": "funny",
287 | "selftext_html": null,
288 | "selftext": "",
289 | "likes": null,
290 | "suggested_sort": null,
291 | "user_reports": [],
292 | "secure_media": null,
293 | "link_flair_text": null,
294 | "id": "4ue7g8",
295 | "from_kind": null,
296 | "gilded": 0,
297 | "archived": false,
298 | "clicked": false,
299 | "report_reasons": null,
300 | "author": "stankydeerbawls",
301 | "media": null,
302 | "score": 7096,
303 | "approved_by": null,
304 | "over_18": false,
305 | "hidden": false,
306 | "preview": {
307 | "images": [
308 | {
309 | "source": {
310 | "url": "https://i.redditmedia.com/ZJEo-C2-3xvQJQORuMjzkgruVC2nzv_SreVZTxfi3lI.jpg?s=8e749f7f8c61fcc4bc0b5518152dd5f6",
311 | "width": 900,
312 | "height": 1200
313 | },
314 | "resolutions": [
315 | {
316 | "url": "https://i.redditmedia.com/ZJEo-C2-3xvQJQORuMjzkgruVC2nzv_SreVZTxfi3lI.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=108&s=98f1cce2784ad8e1d3ff74943a747691",
317 | "width": 108,
318 | "height": 144
319 | },
320 | {
321 | "url": "https://i.redditmedia.com/ZJEo-C2-3xvQJQORuMjzkgruVC2nzv_SreVZTxfi3lI.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=216&s=4b460b6bde8d2c3a97ab6ff6e63a6339",
322 | "width": 216,
323 | "height": 288
324 | },
325 | {
326 | "url": "https://i.redditmedia.com/ZJEo-C2-3xvQJQORuMjzkgruVC2nzv_SreVZTxfi3lI.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=320&s=2386b8af7267d39556c6064aadeb2d5f",
327 | "width": 320,
328 | "height": 426
329 | },
330 | {
331 | "url": "https://i.redditmedia.com/ZJEo-C2-3xvQJQORuMjzkgruVC2nzv_SreVZTxfi3lI.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=640&s=553846974e289f9387eb07e7ef9658fb",
332 | "width": 640,
333 | "height": 853
334 | }
335 | ],
336 | "variants": {},
337 | "id": "RhISwyYjVgjki99hAr7c8C58FgzcPPvo9y2vOoWpZms"
338 | }
339 | ]
340 | },
341 | "num_comments": 234,
342 | "thumbnail": "http://b.thumbs.redditmedia.com/MZaH3i1yy1uOb3RN1UuSWFwiTrXekos-JdSpFlcWGEE.jpg",
343 | "subreddit_id": "t5_2qh33",
344 | "hide_score": false,
345 | "edited": false,
346 | "link_flair_css_class": null,
347 | "author_flair_css_class": null,
348 | "downs": 0,
349 | "secure_media_embed": {},
350 | "saved": false,
351 | "removal_reason": null,
352 | "post_hint": "link",
353 | "stickied": false,
354 | "from": null,
355 | "is_self": false,
356 | "from_id": null,
357 | "permalink": "/r/funny/comments/4ue7g8/captain_obvious_at_todays_padres_vs_nationals_game/",
358 | "locked": false,
359 | "name": "t3_4ue7g8",
360 | "created": 1469411974,
361 | "url": "http://imgur.com/ndGPjZl",
362 | "author_flair_text": null,
363 | "quarantine": false,
364 | "title": "Captain Obvious at today's Padres vs. Nationals game.",
365 | "created_utc": 1469383174,
366 | "distinguished": null,
367 | "mod_reports": [],
368 | "visited": false,
369 | "num_reports": null,
370 | "ups": 7096
371 | }
372 | },
373 | {
374 | "kind": "t3",
375 | "data": {
376 | "domain": "youtube.com",
377 | "banned_by": null,
378 | "media_embed": {
379 | "content": "<iframe width=\"600\" height=\"338\" src=\"https://www.youtube.com/embed/VVV4xeWBIxE?feature=oembed\" frameborder=\"0\" allowfullscreen></iframe>",
380 | "width": 600,
381 | "scrolling": false,
382 | "height": 338
383 | },
384 | "subreddit": "videos",
385 | "selftext_html": null,
386 | "selftext": "",
387 | "likes": null,
388 | "suggested_sort": null,
389 | "user_reports": [],
390 | "secure_media": {
391 | "type": "youtube.com",
392 | "oembed": {
393 | "provider_url": "https://www.youtube.com/",
394 | "version": "1.0",
395 | "title": "Primitive Technology: Forge Blower",
396 | "type": "video",
397 | "thumbnail_width": 480,
398 | "height": 338,
399 | "width": 600,
400 | "html": "<iframe width=\"600\" height=\"338\" src=\"https://www.youtube.com/embed/VVV4xeWBIxE?feature=oembed\" frameborder=\"0\" allowfullscreen></iframe>",
401 | "author_name": "Primitive Technology",
402 | "provider_name": "YouTube",
403 | "thumbnail_url": "https://i.ytimg.com/vi/VVV4xeWBIxE/hqdefault.jpg",
404 | "thumbnail_height": 360,
405 | "author_url": "https://www.youtube.com/channel/UCAL3JXZSzSm8AlZyD3nQdBA"
406 | }
407 | },
408 | "link_flair_text": null,
409 | "id": "4v8w5n",
410 | "from_kind": null,
411 | "gilded": 0,
412 | "archived": false,
413 | "clicked": false,
414 | "report_reasons": null,
415 | "author": "octaviousprime",
416 | "media": {
417 | "type": "youtube.com",
418 | "oembed": {
419 | "provider_url": "https://www.youtube.com/",
420 | "version": "1.0",
421 | "title": "Primitive Technology: Forge Blower",
422 | "type": "video",
423 | "thumbnail_width": 480,
424 | "height": 338,
425 | "width": 600,
426 | "html": "<iframe width=\"600\" height=\"338\" src=\"https://www.youtube.com/embed/VVV4xeWBIxE?feature=oembed\" frameborder=\"0\" allowfullscreen></iframe>",
427 | "author_name": "Primitive Technology",
428 | "provider_name": "YouTube",
429 | "thumbnail_url": "https://i.ytimg.com/vi/VVV4xeWBIxE/hqdefault.jpg",
430 | "thumbnail_height": 360,
431 | "author_url": "https://www.youtube.com/channel/UCAL3JXZSzSm8AlZyD3nQdBA"
432 | }
433 | },
434 | "score": 7090,
435 | "approved_by": null,
436 | "over_18": false,
437 | "hidden": false,
438 | "preview": {
439 | "images": [
440 | {
441 | "source": {
442 | "url": "https://i.redditmedia.com/lmhbmLG9I_br6IFxlRTWbXEffR1mBUOwXP0_8G9XPUg.jpg?s=e31c2039569885902df34292a51eaf62",
443 | "width": 480,
444 | "height": 360
445 | },
446 | "resolutions": [
447 | {
448 | "url": "https://i.redditmedia.com/lmhbmLG9I_br6IFxlRTWbXEffR1mBUOwXP0_8G9XPUg.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=108&s=cc0f4c5993b641650dc07e40751f4c89",
449 | "width": 108,
450 | "height": 81
451 | },
452 | {
453 | "url": "https://i.redditmedia.com/lmhbmLG9I_br6IFxlRTWbXEffR1mBUOwXP0_8G9XPUg.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=216&s=ad6af34e84b75b09f1dc2ff8d7c87077",
454 | "width": 216,
455 | "height": 162
456 | },
457 | {
458 | "url": "https://i.redditmedia.com/lmhbmLG9I_br6IFxlRTWbXEffR1mBUOwXP0_8G9XPUg.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=320&s=7e1d470d49cfd49978bcfb27c9d12fc8",
459 | "width": 320,
460 | "height": 240
461 | }
462 | ],
463 | "variants": {},
464 | "id": "ip4qCoRLhBO62DXn_guHrcs8y6h5Q61kdke18FW4kw4"
465 | }
466 | ]
467 | },
468 | "num_comments": 3168,
469 | "thumbnail": "http://b.thumbs.redditmedia.com/E1R15cPG8TCtC1EMrZvi0rfNwXKpPbeaE-8CqtWWn2E.jpg",
470 | "subreddit_id": "t5_2qh1e",
471 | "hide_score": false,
472 | "edited": false,
473 | "link_flair_css_class": null,
474 | "author_flair_css_class": null,
475 | "downs": 0,
476 | "secure_media_embed": {
477 | "content": "<iframe width=\"600\" height=\"338\" src=\"https://www.youtube.com/embed/VVV4xeWBIxE?feature=oembed\" frameborder=\"0\" allowfullscreen></iframe>",
478 | "width": 600,
479 | "scrolling": false,
480 | "height": 338
481 | },
482 | "saved": false,
483 | "removal_reason": null,
484 | "post_hint": "rich:video",
485 | "stickied": false,
486 | "from": null,
487 | "is_self": false,
488 | "from_id": null,
489 | "permalink": "/r/videos/comments/4v8w5n/primitive_technology_forge_blower/",
490 | "locked": false,
491 | "name": "t3_4v8w5n",
492 | "created": 1469855801,
493 | "url": "https://www.youtube.com/watch?v=VVV4xeWBIxE",
494 | "author_flair_text": null,
495 | "quarantine": false,
496 | "title": "Primitive Technology: Forge Blower",
497 | "created_utc": 1469827001,
498 | "distinguished": null,
499 | "mod_reports": [],
500 | "visited": false,
501 | "num_reports": null,
502 | "ups": 7090
503 | }
504 | },
505 | {
506 | "kind": "t3",
507 | "data": {
508 | "domain": "kwqc.com",
509 | "banned_by": null,
510 | "media_embed": {},
511 | "subreddit": "funny",
512 | "selftext_html": null,
513 | "selftext": "",
514 | "likes": null,
515 | "suggested_sort": null,
516 | "user_reports": [],
517 | "secure_media": null,
518 | "link_flair_text": null,
519 | "id": "4rdi08",
520 | "from_kind": null,
521 | "gilded": 0,
522 | "archived": false,
523 | "clicked": false,
524 | "report_reasons": null,
525 | "author": "relishcuriosity",
526 | "media": null,
527 | "score": 6967,
528 | "approved_by": null,
529 | "over_18": false,
530 | "hidden": false,
531 | "preview": {
532 | "images": [
533 | {
534 | "source": {
535 | "url": "https://i.redditmedia.com/5agyGlS4n3LfLZQMuukOc2sJkvI11UYE-QWwFKn91eo.jpg?s=5fc1654af1ec02b81e9f85532b0aceac",
536 | "width": 311,
537 | "height": 226
538 | },
539 | "resolutions": [
540 | {
541 | "url": "https://i.redditmedia.com/5agyGlS4n3LfLZQMuukOc2sJkvI11UYE-QWwFKn91eo.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=108&s=6c82341e44e5d1697b08edd23d4a744f",
542 | "width": 108,
543 | "height": 78
544 | },
545 | {
546 | "url": "https://i.redditmedia.com/5agyGlS4n3LfLZQMuukOc2sJkvI11UYE-QWwFKn91eo.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=216&s=5af74d5eac2dca383369ebafec5363cd",
547 | "width": 216,
548 | "height": 156
549 | }
550 | ],
551 | "variants": {},
552 | "id": "4dyfSZBYTDwZntBXXPlBliYI08-uUBRJKcZAXCA5XI8"
553 | }
554 | ]
555 | },
556 | "num_comments": 2459,
557 | "thumbnail": "http://b.thumbs.redditmedia.com/qjdnWgHRXq0GpDzR6yX7zV0JlcbrkBrL2WON1sK9qgM.jpg",
558 | "subreddit_id": "t5_2qh33",
559 | "hide_score": false,
560 | "edited": false,
561 | "link_flair_css_class": null,
562 | "author_flair_css_class": null,
563 | "downs": 0,
564 | "secure_media_embed": {},
565 | "saved": false,
566 | "removal_reason": null,
567 | "post_hint": "link",
568 | "stickied": false,
569 | "from": null,
570 | "is_self": false,
571 | "from_id": null,
572 | "permalink": "/r/funny/comments/4rdi08/iowa_man_jailed_for_shooting_fireworks_at_4_am/",
573 | "locked": false,
574 | "name": "t3_4rdi08",
575 | "created": 1467764617,
576 | "url": "https://kwqc.com/2016/07/05/iowa-man-jailed-for-shooting-fireworks-because-this-is-america/",
577 | "author_flair_text": null,
578 | "quarantine": false,
579 | "title": "Iowa man jailed for shooting fireworks at 4 a.m. and telling police he'd shoot more fireworks “with a blunt in his mouth because this is America.” When asked to take a preliminary breathalyzer test, he responded “that he would take a preliminary go [expletive] yourself test.”",
580 | "created_utc": 1467735817,
581 | "distinguished": null,
582 | "mod_reports": [],
583 | "visited": false,
584 | "num_reports": null,
585 | "ups": 6967
586 | }
587 | },
588 | {
589 | "kind": "t3",
590 | "data": {
591 | "domain": "i.reddituploads.com",
592 | "banned_by": null,
593 | "media_embed": {},
594 | "subreddit": "funny",
595 | "selftext_html": null,
596 | "selftext": "",
597 | "likes": null,
598 | "suggested_sort": null,
599 | "user_reports": [],
600 | "secure_media": null,
601 | "link_flair_text": null,
602 | "id": "4tgb6f",
603 | "from_kind": null,
604 | "gilded": 0,
605 | "archived": false,
606 | "clicked": false,
607 | "report_reasons": null,
608 | "author": "wrxryuu",
609 | "media": null,
610 | "score": 6929,
611 | "approved_by": null,
612 | "over_18": false,
613 | "hidden": false,
614 | "preview": {
615 | "images": [
616 | {
617 | "source": {
618 | "url": "https://i.redditmedia.com/PWk7SgcaJLd9IrHnyOehAD1RNfQaZInWcRaMCZSMTfI.jpg?s=4fa52b54de93c3f7288604d1c19932f9",
619 | "width": 539,
620 | "height": 380
621 | },
622 | "resolutions": [
623 | {
624 | "url": "https://i.redditmedia.com/PWk7SgcaJLd9IrHnyOehAD1RNfQaZInWcRaMCZSMTfI.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=108&s=117896e115615da51e7cdeaede007b28",
625 | "width": 108,
626 | "height": 76
627 | },
628 | {
629 | "url": "https://i.redditmedia.com/PWk7SgcaJLd9IrHnyOehAD1RNfQaZInWcRaMCZSMTfI.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=216&s=75eedc5a8765f0249aab97027efe2d80",
630 | "width": 216,
631 | "height": 152
632 | },
633 | {
634 | "url": "https://i.redditmedia.com/PWk7SgcaJLd9IrHnyOehAD1RNfQaZInWcRaMCZSMTfI.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=320&s=20e0db085a38c8769f67fd459dff812a",
635 | "width": 320,
636 | "height": 225
637 | }
638 | ],
639 | "variants": {},
640 | "id": "ZWQVvCfWF6Z7p_LQ8PrA06f230UG6xCrKTx44NBvZso"
641 | }
642 | ]
643 | },
644 | "num_comments": 410,
645 | "thumbnail": "http://b.thumbs.redditmedia.com/GkI1377VKlfCTuz2DA9003R-ozL09x458HlNPLg_3Os.jpg",
646 | "subreddit_id": "t5_2qh33",
647 | "hide_score": false,
648 | "edited": false,
649 | "link_flair_css_class": null,
650 | "author_flair_css_class": null,
651 | "downs": 0,
652 | "secure_media_embed": {},
653 | "saved": false,
654 | "removal_reason": null,
655 | "post_hint": "link",
656 | "stickied": false,
657 | "from": null,
658 | "is_self": false,
659 | "from_id": null,
660 | "permalink": "/r/funny/comments/4tgb6f/finally_a_bathroom_for_me_and_my_magnum_dong/",
661 | "locked": false,
662 | "name": "t3_4tgb6f",
663 | "created": 1468891492,
664 | "url": "https://i.reddituploads.com/484175e3fc37431da402f9e036218b72?fit=max&h=1536&w=1536&s=4754721ed1145a0dc8dec8dff2e135e0",
665 | "author_flair_text": null,
666 | "quarantine": false,
667 | "title": "Finally, a bathroom for me and my magnum dong.",
668 | "created_utc": 1468862692,
669 | "distinguished": null,
670 | "mod_reports": [],
671 | "visited": false,
672 | "num_reports": null,
673 | "ups": 6929
674 | }
675 | },
676 | {
677 | "kind": "t3",
678 | "data": {
679 | "domain": "rt.com",
680 | "banned_by": null,
681 | "media_embed": {},
682 | "subreddit": "worldnews",
683 | "selftext_html": null,
684 | "selftext": "",
685 | "likes": null,
686 | "suggested_sort": null,
687 | "user_reports": [],
688 | "secure_media": null,
689 | "link_flair_text": "Turkey",
690 | "id": "4tq4sd",
691 | "from_kind": null,
692 | "gilded": 0,
693 | "archived": false,
694 | "clicked": false,
695 | "report_reasons": null,
696 | "author": "monkeyseemonkeydoodo",
697 | "media": null,
698 | "score": 6919,
699 | "approved_by": null,
700 | "over_18": false,
701 | "hidden": false,
702 | "num_comments": 5413,
703 | "thumbnail": "",
704 | "subreddit_id": "t5_2qh13",
705 | "hide_score": false,
706 | "edited": false,
707 | "link_flair_css_class": "turkey",
708 | "author_flair_css_class": null,
709 | "downs": 0,
710 | "secure_media_embed": {},
711 | "saved": false,
712 | "removal_reason": null,
713 | "stickied": false,
714 | "from": null,
715 | "is_self": false,
716 | "from_id": null,
717 | "permalink": "/r/worldnews/comments/4tq4sd/all_turkish_academics_banned_from_traveling/",
718 | "locked": false,
719 | "name": "t3_4tq4sd",
720 | "created": 1469030800,
721 | "url": "https://www.rt.com/news/352218-turkey-academics-ban-travel/",
722 | "author_flair_text": null,
723 | "quarantine": false,
724 | "title": "All Turkish academics banned from traveling abroad – report",
725 | "created_utc": 1469002000,
726 | "distinguished": null,
727 | "mod_reports": [],
728 | "visited": false,
729 | "num_reports": null,
730 | "ups": 6919
731 | }
732 | },
733 | {
734 | "kind": "t3",
735 | "data": {
736 | "domain": "washingtonpost.com",
737 | "banned_by": null,
738 | "media_embed": {},
739 | "subreddit": "politics",
740 | "selftext_html": null,
741 | "selftext": "",
742 | "likes": null,
743 | "suggested_sort": null,
744 | "user_reports": [],
745 | "secure_media": null,
746 | "link_flair_text": null,
747 | "id": "4uj3aq",
748 | "from_kind": null,
749 | "gilded": 0,
750 | "archived": false,
751 | "clicked": false,
752 | "report_reasons": null,
753 | "author": "gAlienLifeform",
754 | "media": null,
755 | "score": 6914,
756 | "approved_by": null,
757 | "over_18": false,
758 | "hidden": false,
759 | "preview": {
760 | "images": [
761 | {
762 | "source": {
763 | "url": "https://i.redditmedia.com/enJvXCwXr5zH5s_ekGoV_W8piVKOXRXtbjppXKMbMxA.jpg?s=d8ab2e58e95345597d5cd08de7636164",
764 | "width": 1484,
765 | "height": 1182
766 | },
767 | "resolutions": [
768 | {
769 | "url": "https://i.redditmedia.com/enJvXCwXr5zH5s_ekGoV_W8piVKOXRXtbjppXKMbMxA.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=108&s=3cfadd88e091c6295258400edac72acd",
770 | "width": 108,
771 | "height": 86
772 | },
773 | {
774 | "url": "https://i.redditmedia.com/enJvXCwXr5zH5s_ekGoV_W8piVKOXRXtbjppXKMbMxA.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=216&s=fdac1d62756bdae7868045bcf1dd5cfe",
775 | "width": 216,
776 | "height": 172
777 | },
778 | {
779 | "url": "https://i.redditmedia.com/enJvXCwXr5zH5s_ekGoV_W8piVKOXRXtbjppXKMbMxA.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=320&s=19df38e35128b9dcb7696efc586a8c50",
780 | "width": 320,
781 | "height": 254
782 | },
783 | {
784 | "url": "https://i.redditmedia.com/enJvXCwXr5zH5s_ekGoV_W8piVKOXRXtbjppXKMbMxA.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=640&s=c2f0021317d0ff1e161fe15987aaece4",
785 | "width": 640,
786 | "height": 509
787 | },
788 | {
789 | "url": "https://i.redditmedia.com/enJvXCwXr5zH5s_ekGoV_W8piVKOXRXtbjppXKMbMxA.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=960&s=ec79e72351bfc33c90e2908db9757cb6",
790 | "width": 960,
791 | "height": 764
792 | },
793 | {
794 | "url": "https://i.redditmedia.com/enJvXCwXr5zH5s_ekGoV_W8piVKOXRXtbjppXKMbMxA.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=1080&s=8624c937ddb2736995ddcdaccd1472d9",
795 | "width": 1080,
796 | "height": 860
797 | }
798 | ],
799 | "variants": {},
800 | "id": "Pz--AT62wr-Jq8h1d12yc1J2NovawDXB-puqPwNPuDE"
801 | }
802 | ]
803 | },
804 | "num_comments": 2362,
805 | "thumbnail": "http://a.thumbs.redditmedia.com/o20w1KAF4JUnzkqDhDGSNqWZGuOwdjcheW691VZjVF8.jpg",
806 | "subreddit_id": "t5_2cneq",
807 | "hide_score": false,
808 | "edited": false,
809 | "link_flair_css_class": null,
810 | "author_flair_css_class": null,
811 | "downs": 0,
812 | "secure_media_embed": {},
813 | "saved": false,
814 | "removal_reason": null,
815 | "post_hint": "link",
816 | "stickied": false,
817 | "from": null,
818 | "is_self": false,
819 | "from_id": null,
820 | "permalink": "/r/politics/comments/4uj3aq/it_took_pressure_from_the_white_house_including_a/",
821 | "locked": false,
822 | "name": "t3_4uj3aq",
823 | "created": 1469488511,
824 | "url": "https://www.washingtonpost.com/news/powerpost/paloma/daily-202/2016/07/25/daily-202-with-dws-ouster-on-eve-of-convention-10-questions-for-the-week-ahead-in-philadelphia/57956b5d4acce20505133c10/",
825 | "author_flair_text": null,
826 | "quarantine": false,
827 | "title": "\"It took pressure from the White House – including a phone call with President Obama – to get her to finally see the writing on the wall. Two reliable sources say Wasserman Schultz was trying to make top aides take the fall, rather than take personal responsibility.\"",
828 | "created_utc": 1469459711,
829 | "distinguished": null,
830 | "mod_reports": [],
831 | "visited": false,
832 | "num_reports": null,
833 | "ups": 6914
834 | }
835 | },
836 | {
837 | "kind": "t3",
838 | "data": {
839 | "domain": "independent.co.uk",
840 | "banned_by": null,
841 | "media_embed": {},
842 | "subreddit": "worldnews",
843 | "selftext_html": null,
844 | "selftext": "",
845 | "likes": null,
846 | "suggested_sort": null,
847 | "user_reports": [],
848 | "secure_media": null,
849 | "link_flair_text": null,
850 | "id": "4vmei9",
851 | "from_kind": null,
852 | "gilded": 0,
853 | "archived": false,
854 | "clicked": false,
855 | "report_reasons": null,
856 | "author": "tryin2immigrate",
857 | "media": null,
858 | "score": 6896,
859 | "approved_by": null,
860 | "over_18": false,
861 | "hidden": false,
862 | "num_comments": 5607,
863 | "thumbnail": "",
864 | "subreddit_id": "t5_2qh13",
865 | "hide_score": false,
866 | "edited": false,
867 | "link_flair_css_class": null,
868 | "author_flair_css_class": null,
869 | "downs": 0,
870 | "secure_media_embed": {},
871 | "saved": false,
872 | "removal_reason": null,
873 | "stickied": false,
874 | "from": null,
875 | "is_self": false,
876 | "from_id": null,
877 | "permalink": "/r/worldnews/comments/4vmei9/rio_2016_swimmers_need_to_ingest_only_three/",
878 | "locked": false,
879 | "name": "t3_4vmei9",
880 | "created": 1470085727,
881 | "url": "http://www.independent.co.uk/sport/olympics/rio-2016-water-pollution-virus-risk-danger-swimming-sailing-rowing-chance-of-infection-almost-a7165866.html",
882 | "author_flair_text": null,
883 | "quarantine": false,
884 | "title": "Rio 2016: Swimmers need to ingest only three teaspoons of water to be almost certain of contracting a virus | Olympics | Sport",
885 | "created_utc": 1470056927,
886 | "distinguished": null,
887 | "mod_reports": [],
888 | "visited": false,
889 | "num_reports": null,
890 | "ups": 6896
891 | }
892 | },
893 | {
894 | "kind": "t3",
895 | "data": {
896 | "domain": "rt.com",
897 | "banned_by": null,
898 | "media_embed": {},
899 | "subreddit": "worldnews",
900 | "selftext_html": null,
901 | "selftext": "",
902 | "likes": null,
903 | "suggested_sort": null,
904 | "user_reports": [],
905 | "secure_media": null,
906 | "link_flair_text": "Turkey",
907 | "id": "4u7k9i",
908 | "from_kind": null,
909 | "gilded": 0,
910 | "archived": false,
911 | "clicked": false,
912 | "report_reasons": null,
913 | "author": "P_leoAtrox",
914 | "media": null,
915 | "score": 6890,
916 | "approved_by": null,
917 | "over_18": false,
918 | "hidden": false,
919 | "num_comments": 2424,
920 | "thumbnail": "",
921 | "subreddit_id": "t5_2qh13",
922 | "hide_score": false,
923 | "edited": false,
924 | "link_flair_css_class": "turkey",
925 | "author_flair_css_class": null,
926 | "downs": 0,
927 | "secure_media_embed": {},
928 | "saved": false,
929 | "removal_reason": null,
930 | "stickied": false,
931 | "from": null,
932 | "is_self": false,
933 | "from_id": null,
934 | "permalink": "/r/worldnews/comments/4u7k9i/erdogan_shuts_down_1000_private_schools_1200/",
935 | "locked": false,
936 | "name": "t3_4u7k9i",
937 | "created": 1469294631,
938 | "url": "https://www.rt.com/news/352867-erdogan-closes-schools-emergency/",
939 | "author_flair_text": null,
940 | "quarantine": false,
941 | "title": "Erdogan shuts down 1,000+ private schools, 1,200+ charities, 15 universities",
942 | "created_utc": 1469265831,
943 | "distinguished": null,
944 | "mod_reports": [],
945 | "visited": false,
946 | "num_reports": null,
947 | "ups": 6890
948 | }
949 | },
950 | {
951 | "kind": "t3",
952 | "data": {
953 | "domain": "streamable.com",
954 | "banned_by": null,
955 | "media_embed": {
956 | "content": "<iframe class=\"embedly-embed\" src=\"//cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fstreamable.com%2Fe%2Fh6bd&url=https%3A%2F%2Fstreamable.com%2Fh6bd&image=https%3A%2F%2Fcdn.streamable.com%2Fimage%2Fh6bd.jpg&key=2aa3c4d5f3de4f5b9120b660ad850dc9&type=text%2Fhtml&schema=streamable\" width=\"600\" height=\"338\" scrolling=\"no\" frameborder=\"0\" allowfullscreen></iframe>",
957 | "width": 600,
958 | "scrolling": false,
959 | "height": 338
960 | },
961 | "subreddit": "videos",
962 | "selftext_html": null,
963 | "selftext": "",
964 | "likes": null,
965 | "suggested_sort": null,
966 | "user_reports": [],
967 | "secure_media": {
968 | "type": "streamable.com",
969 | "oembed": {
970 | "provider_url": "https://www.streamable.com",
971 | "description": "Check out this video on Streamable using your phone, tablet or desktop.",
972 | "title": "Streamable - simple video sharing",
973 | "thumbnail_width": 1280,
974 | "height": 338,
975 | "width": 600,
976 | "html": "<iframe class=\"embedly-embed\" src=\"https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fstreamable.com%2Fe%2Fh6bd&url=https%3A%2F%2Fstreamable.com%2Fh6bd&image=https%3A%2F%2Fcdn.streamable.com%2Fimage%2Fh6bd.jpg&key=2aa3c4d5f3de4f5b9120b660ad850dc9&type=text%2Fhtml&schema=streamable\" width=\"600\" height=\"338\" scrolling=\"no\" frameborder=\"0\" allowfullscreen></iframe>",
977 | "version": "1.0",
978 | "provider_name": "Streamable",
979 | "thumbnail_url": "https://i.embed.ly/1/image?url=https%3A%2F%2Fcdn.streamable.com%2Fimage%2Fh6bd.jpg&key=b1e305db91cf4aa5a86b732cc9fffceb",
980 | "type": "video",
981 | "thumbnail_height": 720
982 | }
983 | },
984 | "link_flair_text": null,
985 | "id": "4veyil",
986 | "from_kind": null,
987 | "gilded": 0,
988 | "archived": false,
989 | "clicked": false,
990 | "report_reasons": null,
991 | "author": "GanjaDingo",
992 | "media": {
993 | "type": "streamable.com",
994 | "oembed": {
995 | "provider_url": "https://www.streamable.com",
996 | "description": "Check out this video on Streamable using your phone, tablet or desktop.",
997 | "title": "Streamable - simple video sharing",
998 | "thumbnail_width": 1280,
999 | "height": 338,
1000 | "width": 600,
1001 | "html": "<iframe class=\"embedly-embed\" src=\"//cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fstreamable.com%2Fe%2Fh6bd&url=https%3A%2F%2Fstreamable.com%2Fh6bd&image=https%3A%2F%2Fcdn.streamable.com%2Fimage%2Fh6bd.jpg&key=2aa3c4d5f3de4f5b9120b660ad850dc9&type=text%2Fhtml&schema=streamable\" width=\"600\" height=\"338\" scrolling=\"no\" frameborder=\"0\" allowfullscreen></iframe>",
1002 | "version": "1.0",
1003 | "provider_name": "Streamable",
1004 | "thumbnail_url": "https://cdn.streamable.com/image/h6bd.jpg",
1005 | "type": "video",
1006 | "thumbnail_height": 720
1007 | }
1008 | },
1009 | "score": 6889,
1010 | "approved_by": null,
1011 | "over_18": false,
1012 | "hidden": false,
1013 | "preview": {
1014 | "images": [
1015 | {
1016 | "source": {
1017 | "url": "https://i.redditmedia.com/tIxdAj8qw4K7baJGREegQ5_X3ysahlE2Fr847DdV1x0.jpg?s=f0ee16267169be41a928adf3b6f5b887",
1018 | "width": 1280,
1019 | "height": 720
1020 | },
1021 | "resolutions": [
1022 | {
1023 | "url": "https://i.redditmedia.com/tIxdAj8qw4K7baJGREegQ5_X3ysahlE2Fr847DdV1x0.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=108&s=37d2d756c4159a44928a85e561eb049f",
1024 | "width": 108,
1025 | "height": 60
1026 | },
1027 | {
1028 | "url": "https://i.redditmedia.com/tIxdAj8qw4K7baJGREegQ5_X3ysahlE2Fr847DdV1x0.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=216&s=1d1ad3cf4c4ce467fcc36b937650e170",
1029 | "width": 216,
1030 | "height": 121
1031 | },
1032 | {
1033 | "url": "https://i.redditmedia.com/tIxdAj8qw4K7baJGREegQ5_X3ysahlE2Fr847DdV1x0.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=320&s=46b0c0db5ca9262aaf890d38917045b6",
1034 | "width": 320,
1035 | "height": 180
1036 | },
1037 | {
1038 | "url": "https://i.redditmedia.com/tIxdAj8qw4K7baJGREegQ5_X3ysahlE2Fr847DdV1x0.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=640&s=7053f206e01e01ae94287ba7044c5a83",
1039 | "width": 640,
1040 | "height": 360
1041 | },
1042 | {
1043 | "url": "https://i.redditmedia.com/tIxdAj8qw4K7baJGREegQ5_X3ysahlE2Fr847DdV1x0.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=960&s=f516c2f562c21766c1481c4a8da67ceb",
1044 | "width": 960,
1045 | "height": 540
1046 | },
1047 | {
1048 | "url": "https://i.redditmedia.com/tIxdAj8qw4K7baJGREegQ5_X3ysahlE2Fr847DdV1x0.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=1080&s=937b88c18ef536f61d59e08aa727b78a",
1049 | "width": 1080,
1050 | "height": 607
1051 | }
1052 | ],
1053 | "variants": {},
1054 | "id": "L7h2NTL4EzhrRlu24U05syKoZCpvb8vSoHeb5HAVTLY"
1055 | }
1056 | ]
1057 | },
1058 | "num_comments": 6042,
1059 | "thumbnail": "http://a.thumbs.redditmedia.com/YW19m0PrytN6CbUTYnDwlczE6Hr-yfMMK6K-rkgbe04.jpg",
1060 | "subreddit_id": "t5_2qh1e",
1061 | "hide_score": false,
1062 | "edited": false,
1063 | "link_flair_css_class": null,
1064 | "author_flair_css_class": null,
1065 | "downs": 0,
1066 | "secure_media_embed": {
1067 | "content": "<iframe class=\"embedly-embed\" src=\"https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fstreamable.com%2Fe%2Fh6bd&url=https%3A%2F%2Fstreamable.com%2Fh6bd&image=https%3A%2F%2Fcdn.streamable.com%2Fimage%2Fh6bd.jpg&key=2aa3c4d5f3de4f5b9120b660ad850dc9&type=text%2Fhtml&schema=streamable\" width=\"600\" height=\"338\" scrolling=\"no\" frameborder=\"0\" allowfullscreen></iframe>",
1068 | "width": 600,
1069 | "scrolling": false,
1070 | "height": 338
1071 | },
1072 | "saved": false,
1073 | "removal_reason": null,
1074 | "post_hint": "rich:video",
1075 | "stickied": false,
1076 | "from": null,
1077 | "is_self": false,
1078 | "from_id": null,
1079 | "permalink": "/r/videos/comments/4veyil/a_guy_just_successfully_jumped_from_25000_ft_with/",
1080 | "locked": false,
1081 | "name": "t3_4veyil",
1082 | "created": 1469956077,
1083 | "url": "https://streamable.com/h6bd",
1084 | "author_flair_text": null,
1085 | "quarantine": false,
1086 | "title": "A guy just successfully jumped from 25,000 ft with no parachute, into a net!",
1087 | "created_utc": 1469927277,
1088 | "distinguished": null,
1089 | "mod_reports": [],
1090 | "visited": false,
1091 | "num_reports": null,
1092 | "ups": 6889
1093 | }
1094 | },
1095 | {
1096 | "kind": "t3",
1097 | "data": {
1098 | "domain": "news.com.au",
1099 | "banned_by": null,
1100 | "media_embed": {},
1101 | "subreddit": "worldnews",
1102 | "selftext_html": null,
1103 | "selftext": "",
1104 | "likes": null,
1105 | "suggested_sort": null,
1106 | "user_reports": [],
1107 | "secure_media": null,
1108 | "link_flair_text": null,
1109 | "id": "4uyq4d",
1110 | "from_kind": null,
1111 | "gilded": 0,
1112 | "archived": false,
1113 | "clicked": false,
1114 | "report_reasons": null,
1115 | "author": "arbili",
1116 | "media": null,
1117 | "score": 6865,
1118 | "approved_by": null,
1119 | "over_18": false,
1120 | "hidden": false,
1121 | "num_comments": 3302,
1122 | "thumbnail": "",
1123 | "subreddit_id": "t5_2qh13",
1124 | "hide_score": false,
1125 | "edited": false,
1126 | "link_flair_css_class": null,
1127 | "author_flair_css_class": null,
1128 | "downs": 0,
1129 | "secure_media_embed": {},
1130 | "saved": false,
1131 | "removal_reason": null,
1132 | "stickied": false,
1133 | "from": null,
1134 | "is_self": false,
1135 | "from_id": null,
1136 | "permalink": "/r/worldnews/comments/4uyq4d/rio_2016_olympic_athletes_told_to_keep_your_mouth/",
1137 | "locked": false,
1138 | "name": "t3_4uyq4d",
1139 | "created": 1469706203,
1140 | "url": "http://www.news.com.au/sport/olympics/rio-2016-olympic-athletes-told-to-keep-your-mouth-closed-when-in-contaminated-water/news-story/45e6ae4643f4dbd4001281f669b898c1",
1141 | "author_flair_text": null,
1142 | "quarantine": false,
1143 | "title": "Rio 2016: Olympic athletes told to ‘keep your mouth closed’ when in contaminated water",
1144 | "created_utc": 1469677403,
1145 | "distinguished": null,
1146 | "mod_reports": [],
1147 | "visited": false,
1148 | "num_reports": null,
1149 | "ups": 6865
1150 | }
1151 | },
1152 | {
1153 | "kind": "t3",
1154 | "data": {
1155 | "domain": "i.imgur.com",
1156 | "banned_by": null,
1157 | "media_embed": {},
1158 | "subreddit": "WTF",
1159 | "selftext_html": null,
1160 | "selftext": "",
1161 | "likes": null,
1162 | "suggested_sort": null,
1163 | "user_reports": [],
1164 | "secure_media": null,
1165 | "link_flair_text": null,
1166 | "id": "4v2iz0",
1167 | "from_kind": null,
1168 | "gilded": 0,
1169 | "archived": false,
1170 | "clicked": false,
1171 | "report_reasons": null,
1172 | "author": "ppaed",
1173 | "media": null,
1174 | "score": 6852,
1175 | "approved_by": null,
1176 | "over_18": false,
1177 | "hidden": false,
1178 | "num_comments": 1894,
1179 | "thumbnail": "",
1180 | "subreddit_id": "t5_2qh61",
1181 | "hide_score": false,
1182 | "edited": false,
1183 | "link_flair_css_class": null,
1184 | "author_flair_css_class": null,
1185 | "downs": 0,
1186 | "secure_media_embed": {},
1187 | "saved": false,
1188 | "removal_reason": null,
1189 | "stickied": false,
1190 | "from": null,
1191 | "is_self": false,
1192 | "from_id": null,
1193 | "permalink": "/r/WTF/comments/4v2iz0/man_uses_a_car_wash_hose_to_chase_away_hijackers/",
1194 | "locked": false,
1195 | "name": "t3_4v2iz0",
1196 | "created": 1469763070,
1197 | "url": "http://i.imgur.com/rWmyS6m.gifv",
1198 | "author_flair_text": null,
1199 | "quarantine": false,
1200 | "title": "Man uses a car wash hose to chase away hijackers",
1201 | "created_utc": 1469734270,
1202 | "distinguished": null,
1203 | "mod_reports": [],
1204 | "visited": false,
1205 | "num_reports": null,
1206 | "ups": 6852
1207 | }
1208 | },
1209 | {
1210 | "kind": "t3",
1211 | "data": {
1212 | "domain": "hurriyetdailynews.com",
1213 | "banned_by": null,
1214 | "media_embed": {},
1215 | "subreddit": "worldnews",
1216 | "selftext_html": null,
1217 | "selftext": "",
1218 | "likes": null,
1219 | "suggested_sort": null,
1220 | "user_reports": [],
1221 | "secure_media": null,
1222 | "link_flair_text": "Turkey",
1223 | "id": "4twhwz",
1224 | "from_kind": null,
1225 | "gilded": 0,
1226 | "archived": false,
1227 | "clicked": false,
1228 | "report_reasons": null,
1229 | "author": "r721",
1230 | "media": null,
1231 | "score": 6849,
1232 | "approved_by": null,
1233 | "over_18": false,
1234 | "hidden": false,
1235 | "num_comments": 4523,
1236 | "thumbnail": "",
1237 | "subreddit_id": "t5_2qh13",
1238 | "hide_score": false,
1239 | "edited": false,
1240 | "link_flair_css_class": "turkey",
1241 | "author_flair_css_class": null,
1242 | "downs": 0,
1243 | "secure_media_embed": {},
1244 | "saved": false,
1245 | "removal_reason": null,
1246 | "stickied": false,
1247 | "from": null,
1248 | "is_self": false,
1249 | "from_id": null,
1250 | "permalink": "/r/worldnews/comments/4twhwz/turkey_to_temporarily_suspend_european_convention/",
1251 | "locked": false,
1252 | "name": "t3_4twhwz",
1253 | "created": 1469129013,
1254 | "url": "http://www.hurriyetdailynews.com/turkey-to-temporarily-suspend-european-convention-on-human-rights-after-coup-attempt.aspx?pageID=238&nid=101910&NewsCatID=338",
1255 | "author_flair_text": null,
1256 | "quarantine": false,
1257 | "title": "Turkey to temporarily suspend European Convention on Human Rights after coup attempt",
1258 | "created_utc": 1469100213,
1259 | "distinguished": null,
1260 | "mod_reports": [],
1261 | "visited": false,
1262 | "num_reports": null,
1263 | "ups": 6849
1264 | }
1265 | },
1266 | {
1267 | "kind": "t3",
1268 | "data": {
1269 | "domain": "imgur.com",
1270 | "banned_by": null,
1271 | "media_embed": {},
1272 | "subreddit": "funny",
1273 | "selftext_html": null,
1274 | "selftext": "",
1275 | "likes": null,
1276 | "suggested_sort": null,
1277 | "user_reports": [],
1278 | "secure_media": null,
1279 | "link_flair_text": null,
1280 | "id": "4rhvqx",
1281 | "from_kind": null,
1282 | "gilded": 0,
1283 | "archived": false,
1284 | "clicked": false,
1285 | "report_reasons": null,
1286 | "author": "Jorogasm",
1287 | "media": null,
1288 | "score": 6840,
1289 | "approved_by": null,
1290 | "over_18": false,
1291 | "hidden": false,
1292 | "preview": {
1293 | "images": [
1294 | {
1295 | "source": {
1296 | "url": "https://i.redditmedia.com/3bNZTN3ymXSzasSPSibG7rfkZHvAnB1Kb-5OsaaRatc.jpg?s=50c9c2310e54b2eb89ff20523b1ff196",
1297 | "width": 773,
1298 | "height": 775
1299 | },
1300 | "resolutions": [
1301 | {
1302 | "url": "https://i.redditmedia.com/3bNZTN3ymXSzasSPSibG7rfkZHvAnB1Kb-5OsaaRatc.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=108&s=cd168a148cb86911c066cd218a061eeb",
1303 | "width": 108,
1304 | "height": 108
1305 | },
1306 | {
1307 | "url": "https://i.redditmedia.com/3bNZTN3ymXSzasSPSibG7rfkZHvAnB1Kb-5OsaaRatc.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=216&s=12c1ad51349158dacc5c951e7c4da4e9",
1308 | "width": 216,
1309 | "height": 216
1310 | },
1311 | {
1312 | "url": "https://i.redditmedia.com/3bNZTN3ymXSzasSPSibG7rfkZHvAnB1Kb-5OsaaRatc.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=320&s=c21e984af3379cc52a1290723dfdbf2e",
1313 | "width": 320,
1314 | "height": 320
1315 | },
1316 | {
1317 | "url": "https://i.redditmedia.com/3bNZTN3ymXSzasSPSibG7rfkZHvAnB1Kb-5OsaaRatc.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=640&s=c0e343da018c212c333c3fd9373c1d07",
1318 | "width": 640,
1319 | "height": 641
1320 | }
1321 | ],
1322 | "variants": {},
1323 | "id": "WGAsyHgFyx-CBuRJjOGWZlsO213Lm1KPj1eXH9J1WcU"
1324 | }
1325 | ]
1326 | },
1327 | "num_comments": 1201,
1328 | "thumbnail": "http://a.thumbs.redditmedia.com/o5L9Gnl8aQ63PL7e5JAwTK5AbVV-MTR3DKJWEGD0MQ0.jpg",
1329 | "subreddit_id": "t5_2qh33",
1330 | "hide_score": false,
1331 | "edited": false,
1332 | "link_flair_css_class": null,
1333 | "author_flair_css_class": null,
1334 | "downs": 0,
1335 | "secure_media_embed": {},
1336 | "saved": false,
1337 | "removal_reason": null,
1338 | "post_hint": "link",
1339 | "stickied": false,
1340 | "from": null,
1341 | "is_self": false,
1342 | "from_id": null,
1343 | "permalink": "/r/funny/comments/4rhvqx/is_the_person_naming_these_yarns_okay/",
1344 | "locked": false,
1345 | "name": "t3_4rhvqx",
1346 | "created": 1467830016,
1347 | "url": "http://imgur.com/uoZQEbp",
1348 | "author_flair_text": null,
1349 | "quarantine": false,
1350 | "title": "Is the person naming these yarns okay?",
1351 | "created_utc": 1467801216,
1352 | "distinguished": null,
1353 | "mod_reports": [],
1354 | "visited": false,
1355 | "num_reports": null,
1356 | "ups": 6840
1357 | }
1358 | },
1359 | {
1360 | "kind": "t3",
1361 | "data": {
1362 | "domain": "i.reddituploads.com",
1363 | "banned_by": null,
1364 | "media_embed": {},
1365 | "subreddit": "funny",
1366 | "selftext_html": null,
1367 | "selftext": "",
1368 | "likes": null,
1369 | "suggested_sort": null,
1370 | "user_reports": [],
1371 | "secure_media": null,
1372 | "link_flair_text": null,
1373 | "id": "4t5orl",
1374 | "from_kind": null,
1375 | "gilded": 0,
1376 | "archived": false,
1377 | "clicked": false,
1378 | "report_reasons": null,
1379 | "author": "switchfootball",
1380 | "media": null,
1381 | "score": 6850,
1382 | "approved_by": null,
1383 | "over_18": false,
1384 | "hidden": false,
1385 | "preview": {
1386 | "images": [
1387 | {
1388 | "source": {
1389 | "url": "https://i.redditmedia.com/A0ld4z79PvkSENXJcrmxIwauD6kx2prqho0p7ccjvtk.jpg?s=2716faa5671ef452c278a826a43f870e",
1390 | "width": 1118,
1391 | "height": 1536
1392 | },
1393 | "resolutions": [
1394 | {
1395 | "url": "https://i.redditmedia.com/A0ld4z79PvkSENXJcrmxIwauD6kx2prqho0p7ccjvtk.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=108&s=cacfad8a437f93d976f0658e6c7b7704",
1396 | "width": 108,
1397 | "height": 148
1398 | },
1399 | {
1400 | "url": "https://i.redditmedia.com/A0ld4z79PvkSENXJcrmxIwauD6kx2prqho0p7ccjvtk.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=216&s=d4c1fbeb9aca9accbfc37425a612693a",
1401 | "width": 216,
1402 | "height": 296
1403 | },
1404 | {
1405 | "url": "https://i.redditmedia.com/A0ld4z79PvkSENXJcrmxIwauD6kx2prqho0p7ccjvtk.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=320&s=ab546fb6d2866388cd3b89e5e560685e",
1406 | "width": 320,
1407 | "height": 439
1408 | },
1409 | {
1410 | "url": "https://i.redditmedia.com/A0ld4z79PvkSENXJcrmxIwauD6kx2prqho0p7ccjvtk.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=640&s=5a71301700fe12c12544bbc464e0dcd4",
1411 | "width": 640,
1412 | "height": 879
1413 | },
1414 | {
1415 | "url": "https://i.redditmedia.com/A0ld4z79PvkSENXJcrmxIwauD6kx2prqho0p7ccjvtk.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=960&s=a74c1acc20af90c50665eafaeeaae980",
1416 | "width": 960,
1417 | "height": 1318
1418 | },
1419 | {
1420 | "url": "https://i.redditmedia.com/A0ld4z79PvkSENXJcrmxIwauD6kx2prqho0p7ccjvtk.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=1080&s=8c569d8da5f2bdb0bfa6758228758b4b",
1421 | "width": 1080,
1422 | "height": 1483
1423 | }
1424 | ],
1425 | "variants": {},
1426 | "id": "CUK3Fcc-7uNHMd-aVUeLuBaY9cAfWulzWoS75Py-8uk"
1427 | }
1428 | ]
1429 | },
1430 | "num_comments": 2155,
1431 | "thumbnail": "http://b.thumbs.redditmedia.com/3vCLlXJqLbm9-QL-gyeqR2XGAEK8MmPSsmzNoZErOIg.jpg",
1432 | "subreddit_id": "t5_2qh33",
1433 | "hide_score": false,
1434 | "edited": false,
1435 | "link_flair_css_class": null,
1436 | "author_flair_css_class": null,
1437 | "downs": 0,
1438 | "secure_media_embed": {},
1439 | "saved": false,
1440 | "removal_reason": null,
1441 | "post_hint": "link",
1442 | "stickied": false,
1443 | "from": null,
1444 | "is_self": false,
1445 | "from_id": null,
1446 | "permalink": "/r/funny/comments/4t5orl/year_no_4_at_my_wifes_family_reunion/",
1447 | "locked": false,
1448 | "name": "t3_4t5orl",
1449 | "created": 1468721064,
1450 | "url": "https://i.reddituploads.com/902c882162eb452e91bb3e207de6fef1?fit=max&h=1536&w=1536&s=1199c1148974dd21827a2732a4a15cfd",
1451 | "author_flair_text": null,
1452 | "quarantine": false,
1453 | "title": "Year No. 4 at my wife's family reunion.",
1454 | "created_utc": 1468692264,
1455 | "distinguished": null,
1456 | "mod_reports": [],
1457 | "visited": false,
1458 | "num_reports": null,
1459 | "ups": 6850
1460 | }
1461 | },
1462 | {
1463 | "kind": "t3",
1464 | "data": {
1465 | "domain": "top40.about.com",
1466 | "banned_by": null,
1467 | "media_embed": {},
1468 | "subreddit": "todayilearned",
1469 | "selftext_html": null,
1470 | "selftext": "",
1471 | "likes": null,
1472 | "suggested_sort": null,
1473 | "user_reports": [],
1474 | "secure_media": null,
1475 | "link_flair_text": null,
1476 | "id": "4r6uds",
1477 | "from_kind": null,
1478 | "gilded": 0,
1479 | "archived": false,
1480 | "clicked": false,
1481 | "report_reasons": null,
1482 | "author": "BizarroCullen",
1483 | "media": null,
1484 | "score": 6831,
1485 | "approved_by": null,
1486 | "over_18": false,
1487 | "hidden": false,
1488 | "preview": {
1489 | "images": [
1490 | {
1491 | "source": {
1492 | "url": "https://i.redditmedia.com/sISKTjEGKTGmHZgSGrKCD-mKsX1SwV-g6595wVfKK24.jpg?s=cab24ab18027c3ca83d6b876a903cdc5",
1493 | "width": 640,
1494 | "height": 427
1495 | },
1496 | "resolutions": [
1497 | {
1498 | "url": "https://i.redditmedia.com/sISKTjEGKTGmHZgSGrKCD-mKsX1SwV-g6595wVfKK24.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=108&s=6d6976393c247bbc7af4e06d40ecf570",
1499 | "width": 108,
1500 | "height": 72
1501 | },
1502 | {
1503 | "url": "https://i.redditmedia.com/sISKTjEGKTGmHZgSGrKCD-mKsX1SwV-g6595wVfKK24.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=216&s=e1211ee901266cbfdc3c02aa8a1f77c4",
1504 | "width": 216,
1505 | "height": 144
1506 | },
1507 | {
1508 | "url": "https://i.redditmedia.com/sISKTjEGKTGmHZgSGrKCD-mKsX1SwV-g6595wVfKK24.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=320&s=62bed020bde0d0e01d425c0b1a393fc3",
1509 | "width": 320,
1510 | "height": 213
1511 | },
1512 | {
1513 | "url": "https://i.redditmedia.com/sISKTjEGKTGmHZgSGrKCD-mKsX1SwV-g6595wVfKK24.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=640&s=7a0a8e4a74340ed21bf9482fee86f30f",
1514 | "width": 640,
1515 | "height": 427
1516 | }
1517 | ],
1518 | "variants": {},
1519 | "id": "6O02hpI52C-pZy9RmoaFD200Txy8X_N-KjkL27NwSPw"
1520 | }
1521 | ]
1522 | },
1523 | "num_comments": 473,
1524 | "thumbnail": "http://a.thumbs.redditmedia.com/HjsEQHBl3ttz3h3kX0PcIXTku37bhzBTobXsfL0yFT8.jpg",
1525 | "subreddit_id": "t5_2qqjc",
1526 | "hide_score": false,
1527 | "edited": false,
1528 | "link_flair_css_class": null,
1529 | "author_flair_css_class": null,
1530 | "downs": 0,
1531 | "secure_media_embed": {},
1532 | "saved": false,
1533 | "removal_reason": null,
1534 | "post_hint": "link",
1535 | "stickied": false,
1536 | "from": null,
1537 | "is_self": false,
1538 | "from_id": null,
1539 | "permalink": "/r/todayilearned/comments/4r6uds/til_that_the_reason_top_40_has_specifically_forty/",
1540 | "locked": false,
1541 | "name": "t3_4r6uds",
1542 | "created": 1467661057,
1543 | "url": "http://top40.about.com/od/popmusic101/a/top40.htm",
1544 | "author_flair_text": null,
1545 | "quarantine": false,
1546 | "title": "TIL that the reason Top 40 has specifically forty singles is because standard jukebox machines held 40 songs at that time.",
1547 | "created_utc": 1467632257,
1548 | "distinguished": null,
1549 | "mod_reports": [],
1550 | "visited": false,
1551 | "num_reports": null,
1552 | "ups": 6831
1553 | }
1554 | },
1555 | {
1556 | "kind": "t3",
1557 | "data": {
1558 | "domain": "theintercept.com",
1559 | "banned_by": null,
1560 | "media_embed": {},
1561 | "subreddit": "worldnews",
1562 | "selftext_html": null,
1563 | "selftext": "",
1564 | "likes": null,
1565 | "suggested_sort": null,
1566 | "user_reports": [],
1567 | "secure_media": null,
1568 | "link_flair_text": null,
1569 | "id": "4tc8x5",
1570 | "from_kind": null,
1571 | "gilded": 0,
1572 | "archived": false,
1573 | "clicked": false,
1574 | "report_reasons": null,
1575 | "author": "bodobobo",
1576 | "media": null,
1577 | "score": 6834,
1578 | "approved_by": null,
1579 | "over_18": false,
1580 | "hidden": false,
1581 | "num_comments": 3894,
1582 | "thumbnail": "",
1583 | "subreddit_id": "t5_2qh13",
1584 | "hide_score": false,
1585 | "edited": false,
1586 | "link_flair_css_class": null,
1587 | "author_flair_css_class": null,
1588 | "downs": 0,
1589 | "secure_media_embed": {},
1590 | "saved": false,
1591 | "removal_reason": null,
1592 | "stickied": false,
1593 | "from": null,
1594 | "is_self": false,
1595 | "from_id": null,
1596 | "permalink": "/r/worldnews/comments/4tc8x5/saudi_ties_to_911_detailed_in_documents/",
1597 | "locked": false,
1598 | "name": "t3_4tc8x5",
1599 | "created": 1468828189,
1600 | "url": "https://theintercept.com/2016/07/15/saudi-ties-to-911-detailed-in-documents-suppressed-since-2002/",
1601 | "author_flair_text": null,
1602 | "quarantine": false,
1603 | "title": "Saudi Ties to 9/11 Detailed in Documents Suppressed Since 2002",
1604 | "created_utc": 1468799389,
1605 | "distinguished": null,
1606 | "mod_reports": [],
1607 | "visited": false,
1608 | "num_reports": null,
1609 | "ups": 6834
1610 | }
1611 | },
1612 | {
1613 | "kind": "t3",
1614 | "data": {
1615 | "domain": "i.reddituploads.com",
1616 | "banned_by": null,
1617 | "media_embed": {},
1618 | "subreddit": "funny",
1619 | "selftext_html": null,
1620 | "selftext": "",
1621 | "likes": null,
1622 | "suggested_sort": null,
1623 | "user_reports": [],
1624 | "secure_media": null,
1625 | "link_flair_text": null,
1626 | "id": "4t3j2f",
1627 | "from_kind": null,
1628 | "gilded": 0,
1629 | "archived": false,
1630 | "clicked": false,
1631 | "report_reasons": null,
1632 | "author": "batgaz",
1633 | "media": null,
1634 | "score": 6792,
1635 | "approved_by": null,
1636 | "over_18": false,
1637 | "hidden": false,
1638 | "preview": {
1639 | "images": [
1640 | {
1641 | "source": {
1642 | "url": "https://i.redditmedia.com/vIp24QjVtWBP-bn7hFJDDj3SfYjrSy3A1BhX6hmnYaI.jpg?s=0cc33e02308ad0c48b9b24340032557a",
1643 | "width": 720,
1644 | "height": 960
1645 | },
1646 | "resolutions": [
1647 | {
1648 | "url": "https://i.redditmedia.com/vIp24QjVtWBP-bn7hFJDDj3SfYjrSy3A1BhX6hmnYaI.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=108&s=b08f33079ac749a4b295bed6398f23e3",
1649 | "width": 108,
1650 | "height": 144
1651 | },
1652 | {
1653 | "url": "https://i.redditmedia.com/vIp24QjVtWBP-bn7hFJDDj3SfYjrSy3A1BhX6hmnYaI.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=216&s=8a88c8187763ea5416e8a9d54f365f78",
1654 | "width": 216,
1655 | "height": 288
1656 | },
1657 | {
1658 | "url": "https://i.redditmedia.com/vIp24QjVtWBP-bn7hFJDDj3SfYjrSy3A1BhX6hmnYaI.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=320&s=2da7d2f54d77b92ac23d1442c6c1bd99",
1659 | "width": 320,
1660 | "height": 426
1661 | },
1662 | {
1663 | "url": "https://i.redditmedia.com/vIp24QjVtWBP-bn7hFJDDj3SfYjrSy3A1BhX6hmnYaI.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=640&s=2a7c853330d894e5a90dae86badb1a22",
1664 | "width": 640,
1665 | "height": 853
1666 | }
1667 | ],
1668 | "variants": {},
1669 | "id": "fbKclQJBXqsRSnpBZKVs1YDTim_4UQTDWheUcltniqo"
1670 | }
1671 | ]
1672 | },
1673 | "num_comments": 1245,
1674 | "thumbnail": "http://b.thumbs.redditmedia.com/yyaAik8v8W0rggroagtAhyhECylVkVTdOHIwekZz2jk.jpg",
1675 | "subreddit_id": "t5_2qh33",
1676 | "hide_score": false,
1677 | "edited": false,
1678 | "link_flair_css_class": null,
1679 | "author_flair_css_class": null,
1680 | "downs": 0,
1681 | "secure_media_embed": {},
1682 | "saved": false,
1683 | "removal_reason": null,
1684 | "post_hint": "link",
1685 | "stickied": false,
1686 | "from": null,
1687 | "is_self": false,
1688 | "from_id": null,
1689 | "permalink": "/r/funny/comments/4t3j2f/my_pregnant_wife_sent_this_to_me_at_212am_this/",
1690 | "locked": false,
1691 | "name": "t3_4t3j2f",
1692 | "created": 1468681404,
1693 | "url": "https://i.reddituploads.com/f60774811e5c42848d394d396d7df083?fit=max&h=1536&w=1536&s=214279a4d106d58c2be80b6f7545239c",
1694 | "author_flair_text": null,
1695 | "quarantine": false,
1696 | "title": "My pregnant wife sent this to me at 2:12am this morning. I'm going to guess that my snoring was quite bad last night.",
1697 | "created_utc": 1468652604,
1698 | "distinguished": null,
1699 | "mod_reports": [],
1700 | "visited": false,
1701 | "num_reports": null,
1702 | "ups": 6792
1703 | }
1704 | },
1705 | {
1706 | "kind": "t3",
1707 | "data": {
1708 | "domain": "news.com.au",
1709 | "banned_by": null,
1710 | "media_embed": {},
1711 | "subreddit": "worldnews",
1712 | "selftext_html": null,
1713 | "selftext": "",
1714 | "likes": null,
1715 | "suggested_sort": null,
1716 | "user_reports": [],
1717 | "secure_media": null,
1718 | "link_flair_text": null,
1719 | "id": "4szcpz",
1720 | "from_kind": null,
1721 | "gilded": 0,
1722 | "archived": false,
1723 | "clicked": false,
1724 | "report_reasons": null,
1725 | "author": "itoitoito",
1726 | "media": null,
1727 | "score": 6785,
1728 | "approved_by": null,
1729 | "over_18": false,
1730 | "hidden": false,
1731 | "num_comments": 2787,
1732 | "thumbnail": "",
1733 | "subreddit_id": "t5_2qh13",
1734 | "hide_score": false,
1735 | "edited": false,
1736 | "link_flair_css_class": null,
1737 | "author_flair_css_class": null,
1738 | "downs": 0,
1739 | "secure_media_embed": {},
1740 | "saved": false,
1741 | "removal_reason": null,
1742 | "stickied": false,
1743 | "from": null,
1744 | "is_self": false,
1745 | "from_id": null,
1746 | "permalink": "/r/worldnews/comments/4szcpz/asbestos_found_in_new_12b_perth_childrens/",
1747 | "locked": false,
1748 | "name": "t3_4szcpz",
1749 | "created": 1468621784,
1750 | "url": "http://www.news.com.au/lifestyle/health/asbestos-found-in-new-12b-perth-childrens-hospital/news-story/2c391ab14fe220ebaeeee42b41cafa0a",
1751 | "author_flair_text": null,
1752 | "quarantine": false,
1753 | "title": "Asbestos found in new $1.2b Perth children’s hospital - roof panels made in China",
1754 | "created_utc": 1468592984,
1755 | "distinguished": null,
1756 | "mod_reports": [],
1757 | "visited": false,
1758 | "num_reports": null,
1759 | "ups": 6785
1760 | }
1761 | },
1762 | {
1763 | "kind": "t3",
1764 | "data": {
1765 | "domain": "i.imgur.com",
1766 | "banned_by": null,
1767 | "media_embed": {},
1768 | "subreddit": "WTF",
1769 | "selftext_html": null,
1770 | "selftext": "",
1771 | "likes": null,
1772 | "suggested_sort": null,
1773 | "user_reports": [],
1774 | "secure_media": null,
1775 | "link_flair_text": null,
1776 | "id": "4up25e",
1777 | "from_kind": null,
1778 | "gilded": 0,
1779 | "archived": false,
1780 | "clicked": false,
1781 | "report_reasons": null,
1782 | "author": "Magmafat",
1783 | "media": null,
1784 | "score": 6778,
1785 | "approved_by": null,
1786 | "over_18": false,
1787 | "hidden": false,
1788 | "num_comments": 1909,
1789 | "thumbnail": "",
1790 | "subreddit_id": "t5_2qh61",
1791 | "hide_score": false,
1792 | "edited": false,
1793 | "link_flair_css_class": null,
1794 | "author_flair_css_class": null,
1795 | "downs": 0,
1796 | "secure_media_embed": {},
1797 | "saved": false,
1798 | "removal_reason": null,
1799 | "stickied": false,
1800 | "from": null,
1801 | "is_self": false,
1802 | "from_id": null,
1803 | "permalink": "/r/WTF/comments/4up25e/rio_cocaine_dealers_now_using_the_olympic_logo/",
1804 | "locked": false,
1805 | "name": "t3_4up25e",
1806 | "created": 1469574204,
1807 | "url": "http://i.imgur.com/2YiwhCe.jpg",
1808 | "author_flair_text": null,
1809 | "quarantine": false,
1810 | "title": "Rio cocaine dealers now using the Olympic logo, plus the warning \"don't use near children\"",
1811 | "created_utc": 1469545404,
1812 | "distinguished": null,
1813 | "mod_reports": [],
1814 | "visited": false,
1815 | "num_reports": null,
1816 | "ups": 6778
1817 | }
1818 | },
1819 | {
1820 | "kind": "t3",
1821 | "data": {
1822 | "domain": "streamable.com",
1823 | "banned_by": null,
1824 | "media_embed": {
1825 | "content": "<iframe class=\"embedly-embed\" src=\"//cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fstreamable.com%2Fe%2Fsqj4&url=https%3A%2F%2Fstreamable.com%2Fsqj4&image=http%3A%2F%2Fcdn.streamable.com%2Fimage%2Fsqj4.jpg&key=2aa3c4d5f3de4f5b9120b660ad850dc9&type=text%2Fhtml&schema=streamable\" width=\"398\" height=\"224\" scrolling=\"no\" frameborder=\"0\" allowfullscreen></iframe>",
1826 | "width": 398,
1827 | "scrolling": false,
1828 | "height": 224
1829 | },
1830 | "subreddit": "videos",
1831 | "selftext_html": null,
1832 | "selftext": "",
1833 | "likes": null,
1834 | "suggested_sort": null,
1835 | "user_reports": [],
1836 | "secure_media": {
1837 | "type": "streamable.com",
1838 | "oembed": {
1839 | "provider_url": "https://www.streamable.com",
1840 | "description": "Check out this video on Streamable using your phone, tablet or desktop.",
1841 | "title": "Streamable - simple video sharing",
1842 | "thumbnail_width": 398,
1843 | "height": 224,
1844 | "width": 398,
1845 | "html": "<iframe class=\"embedly-embed\" src=\"https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fstreamable.com%2Fe%2Fsqj4&url=https%3A%2F%2Fstreamable.com%2Fsqj4&image=http%3A%2F%2Fcdn.streamable.com%2Fimage%2Fsqj4.jpg&key=2aa3c4d5f3de4f5b9120b660ad850dc9&type=text%2Fhtml&schema=streamable\" width=\"398\" height=\"224\" scrolling=\"no\" frameborder=\"0\" allowfullscreen></iframe>",
1846 | "version": "1.0",
1847 | "provider_name": "Streamable",
1848 | "thumbnail_url": "https://i.embed.ly/1/image?url=http%3A%2F%2Fcdn.streamable.com%2Fimage%2Fsqj4.jpg&key=b1e305db91cf4aa5a86b732cc9fffceb",
1849 | "type": "video",
1850 | "thumbnail_height": 224
1851 | }
1852 | },
1853 | "link_flair_text": null,
1854 | "id": "4s8mz8",
1855 | "from_kind": null,
1856 | "gilded": 0,
1857 | "archived": false,
1858 | "clicked": false,
1859 | "report_reasons": null,
1860 | "author": "ItsComingHomeLads",
1861 | "media": {
1862 | "type": "streamable.com",
1863 | "oembed": {
1864 | "provider_url": "https://www.streamable.com",
1865 | "description": "Check out this video on Streamable using your phone, tablet or desktop.",
1866 | "title": "Streamable - simple video sharing",
1867 | "thumbnail_width": 398,
1868 | "height": 224,
1869 | "width": 398,
1870 | "html": "<iframe class=\"embedly-embed\" src=\"//cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fstreamable.com%2Fe%2Fsqj4&url=https%3A%2F%2Fstreamable.com%2Fsqj4&image=http%3A%2F%2Fcdn.streamable.com%2Fimage%2Fsqj4.jpg&key=2aa3c4d5f3de4f5b9120b660ad850dc9&type=text%2Fhtml&schema=streamable\" width=\"398\" height=\"224\" scrolling=\"no\" frameborder=\"0\" allowfullscreen></iframe>",
1871 | "version": "1.0",
1872 | "provider_name": "Streamable",
1873 | "thumbnail_url": "http://cdn.streamable.com/image/sqj4.jpg",
1874 | "type": "video",
1875 | "thumbnail_height": 224
1876 | }
1877 | },
1878 | "score": 6757,
1879 | "approved_by": null,
1880 | "over_18": false,
1881 | "hidden": false,
1882 | "preview": {
1883 | "images": [
1884 | {
1885 | "source": {
1886 | "url": "https://i.redditmedia.com/WioQndKL8Xxds0dRzg_Ze10H0D9VSw6ggHc0vN3b8hI.jpg?s=5bd637e6a340bc17dc5e144003ade4a2",
1887 | "width": 398,
1888 | "height": 224
1889 | },
1890 | "resolutions": [
1891 | {
1892 | "url": "https://i.redditmedia.com/WioQndKL8Xxds0dRzg_Ze10H0D9VSw6ggHc0vN3b8hI.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=108&s=f2abb8b7143c7dd6ff92dfe20402b52b",
1893 | "width": 108,
1894 | "height": 60
1895 | },
1896 | {
1897 | "url": "https://i.redditmedia.com/WioQndKL8Xxds0dRzg_Ze10H0D9VSw6ggHc0vN3b8hI.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=216&s=75750143ef67bc21747b32752960cb0a",
1898 | "width": 216,
1899 | "height": 121
1900 | },
1901 | {
1902 | "url": "https://i.redditmedia.com/WioQndKL8Xxds0dRzg_Ze10H0D9VSw6ggHc0vN3b8hI.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=320&s=8a8c8a00e95853bce6c2920457b3b31d",
1903 | "width": 320,
1904 | "height": 180
1905 | }
1906 | ],
1907 | "variants": {},
1908 | "id": "_mAC11s9fu8TLYt5EcOq-gFNlW2Dqa2IQnwUQ0mtagI"
1909 | }
1910 | ]
1911 | },
1912 | "num_comments": 2179,
1913 | "thumbnail": "http://b.thumbs.redditmedia.com/2mgB-d0E-R79-QZWEa83hZfVpbpTS6KwLJxv1xdMeWY.jpg",
1914 | "subreddit_id": "t5_2qh1e",
1915 | "hide_score": false,
1916 | "edited": false,
1917 | "link_flair_css_class": null,
1918 | "author_flair_css_class": null,
1919 | "downs": 0,
1920 | "secure_media_embed": {
1921 | "content": "<iframe class=\"embedly-embed\" src=\"https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fstreamable.com%2Fe%2Fsqj4&url=https%3A%2F%2Fstreamable.com%2Fsqj4&image=http%3A%2F%2Fcdn.streamable.com%2Fimage%2Fsqj4.jpg&key=2aa3c4d5f3de4f5b9120b660ad850dc9&type=text%2Fhtml&schema=streamable\" width=\"398\" height=\"224\" scrolling=\"no\" frameborder=\"0\" allowfullscreen></iframe>",
1922 | "width": 398,
1923 | "scrolling": false,
1924 | "height": 224
1925 | },
1926 | "saved": false,
1927 | "removal_reason": null,
1928 | "post_hint": "rich:video",
1929 | "stickied": false,
1930 | "from": null,
1931 | "is_self": false,
1932 | "from_id": null,
1933 | "permalink": "/r/videos/comments/4s8mz8/little_portuguese_fan_consoling_a_frenchman_after/",
1934 | "locked": false,
1935 | "name": "t3_4s8mz8",
1936 | "created": 1468231680,
1937 | "url": "https://streamable.com/sqj4",
1938 | "author_flair_text": null,
1939 | "quarantine": false,
1940 | "title": "Little Portuguese fan consoling a Frenchman after their loss",
1941 | "created_utc": 1468202880,
1942 | "distinguished": null,
1943 | "mod_reports": [],
1944 | "visited": false,
1945 | "num_reports": null,
1946 | "ups": 6757
1947 | }
1948 | },
1949 | {
1950 | "kind": "t3",
1951 | "data": {
1952 | "domain": "abcnews.go.com",
1953 | "banned_by": null,
1954 | "media_embed": {},
1955 | "subreddit": "politics",
1956 | "selftext_html": null,
1957 | "selftext": "",
1958 | "likes": null,
1959 | "suggested_sort": null,
1960 | "user_reports": [],
1961 | "secure_media": null,
1962 | "link_flair_text": null,
1963 | "id": "4uilgl",
1964 | "from_kind": null,
1965 | "gilded": 0,
1966 | "archived": false,
1967 | "clicked": false,
1968 | "report_reasons": null,
1969 | "author": "Schwa142",
1970 | "media": null,
1971 | "score": 6739,
1972 | "approved_by": null,
1973 | "over_18": false,
1974 | "hidden": false,
1975 | "num_comments": 3462,
1976 | "thumbnail": "default",
1977 | "subreddit_id": "t5_2cneq",
1978 | "hide_score": false,
1979 | "edited": false,
1980 | "link_flair_css_class": null,
1981 | "author_flair_css_class": null,
1982 | "downs": 0,
1983 | "secure_media_embed": {},
1984 | "saved": false,
1985 | "removal_reason": null,
1986 | "stickied": false,
1987 | "from": null,
1988 | "is_self": false,
1989 | "from_id": null,
1990 | "permalink": "/r/politics/comments/4uilgl/debbie_wasserman_schultz_booed_at_chaotic_florida/",
1991 | "locked": false,
1992 | "name": "t3_4uilgl",
1993 | "created": 1469482207,
1994 | "url": "http://abcnews.go.com/Politics/debbie-wasserman-schultz-booed-chaotic-florida-delegation-breakfast/story?id=40850654",
1995 | "author_flair_text": null,
1996 | "quarantine": false,
1997 | "title": "Debbie Wasserman Schultz Booed at Chaotic Florida Delegation Breakfast",
1998 | "created_utc": 1469453407,
1999 | "distinguished": null,
2000 | "mod_reports": [],
2001 | "visited": false,
2002 | "num_reports": null,
2003 | "ups": 6739
2004 | }
2005 | }
2006 | ],
2007 | "after": "t3_4uilgl",
2008 | "before": null
2009 | }
2010 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.1.2'
9 | classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
10 | classpath 'me.tatarka:gradle-retrolambda:3.2.5'
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | jcenter()
17 | }
18 | }
19 |
20 | task clean(type: Delete) {
21 | delete rootProject.buildDir
22 | }
23 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codevate/mvvm-reddit/f6d4d1a525370dbe6bd66eca0ab2c493777e3a68/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Dec 28 10:00:20 PST 2015
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/images/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codevate/mvvm-reddit/f6d4d1a525370dbe6bd66eca0ab2c493777e3a68/images/screenshot.png
--------------------------------------------------------------------------------
/images/screenshot_full.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codevate/mvvm-reddit/f6d4d1a525370dbe6bd66eca0ab2c493777e3a68/images/screenshot_full.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------