diff --git a/app/Http/Controllers/DiscoverController.php b/app/Http/Controllers/DiscoverController.php index 4f443ed2d..9bc48c7a4 100644 --- a/app/Http/Controllers/DiscoverController.php +++ b/app/Http/Controllers/DiscoverController.php @@ -16,6 +16,7 @@ use Auth, DB, Cache; use Illuminate\Http\Request; use App\Transformer\Api\AccountTransformer; use App\Transformer\Api\AccountWithStatusesTransformer; +use App\Transformer\Api\StatusTransformer; use App\Transformer\Api\StatusStatelessTransformer; use League\Fractal; use League\Fractal\Serializer\ArraySerializer; @@ -165,4 +166,74 @@ class DiscoverController extends Controller return $res; } + + public function trendingApi(Request $request) + { + $this->validate($request, [ + 'range' => 'nullable|string|in:daily,monthly,alltime' + ]); + + $range = $request->filled('range') ? + $request->input('range') == 'alltime' ? '-1' : + ($request->input('range') == 'daily' ? 1 : 31) : 1; + + $key = ':api:discover:trending:v1:range:' . $range; + $ttl = now()->addHours(2); + $res = Cache::remember($key, $ttl, function() use($range) { + if($range == '-1') { + $res = Status::orderBy('likes_count','desc') + ->take(12) + ->get(); + } else { + $res = Status::orderBy('likes_count','desc') + ->take(12) + ->where('created_at', '>', now()->subDays($range)) + ->get(); + } + $resource = new Fractal\Resource\Collection($res, new StatusStatelessTransformer()); + return $this->fractal->createData($resource)->toArray(); + }); + return response()->json($res, 200, [], JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES); + } + + public function trendingHashtags(Request $request) + { + $res = StatusHashtag::select('hashtag_id', \DB::raw('count(*) as total')) + ->groupBy('hashtag_id') + ->orderBy('total','desc') + ->where('created_at', '>', now()->subDays(4)) + ->take(9) + ->get() + ->map(function($h) { + $hashtag = $h->hashtag; + return [ + 'id' => $hashtag->id, + 'total' => $h->total, + 'name' => '#'.$hashtag->name, + 'url' => $hashtag->url('?src=dsh1') + ]; + }); + return $res; + } + + public function trendingPlaces(Request $request) + { + $res = Status::select('place_id',DB::raw('count(place_id) as total')) + ->whereNotNull('place_id') + ->where('created_at','>',now()->subDays(14)) + ->groupBy('place_id') + ->orderBy('total') + ->limit(4) + ->get() + ->map(function($s){ + $p = $s->place; + return [ + 'name' => $p->name, + 'country' => $p->country, + 'url' => $p->url() + ]; + }); + + return $res; + } } diff --git a/app/Http/Controllers/InternalApiController.php b/app/Http/Controllers/InternalApiController.php index 31ecd2563..4947e8c2e 100644 --- a/app/Http/Controllers/InternalApiController.php +++ b/app/Http/Controllers/InternalApiController.php @@ -95,7 +95,7 @@ class InternalApiController extends Controller ->with('media') ->inRandomOrder() ->latest() - ->take(37) + ->take(39) ->get(); $res = [ diff --git a/resources/assets/js/components/DiscoverComponent.vue b/resources/assets/js/components/DiscoverComponent.vue index 8f2f6350e..34bbe3224 100644 --- a/resources/assets/js/components/DiscoverComponent.vue +++ b/resources/assets/js/components/DiscoverComponent.vue @@ -4,39 +4,111 @@
-
- +
+
-
-

DISCOVER

+
+

DISCOVER

+

DISCOVER

-
- - -

{{category.name}}

-
+ +
+
+ + {{tag.name}} +
+
-
+ +
-
+
+

Trending

+

Trending

+
+
+ + +
+
+
+
+ +
+
+ +
+
+
+
+

Categories

+

Categories

+
+
+
+ +

{{category.name}}

+
+ +
+
+
+
+
+
+
+

Discover. Categories.

+

Discover. Categories.

+

Discover amazing posts, people, places and hashtags.

+
+
+
+
+
+
+
+ + +
+

For You

+

For You

-
-

To view more posts, check the home or local timelines.

-
+
@@ -98,15 +226,23 @@ loaded: false, config: window.App.config, posts: {}, + hashtags: {}, + places: {}, trending: {}, + trendingDaily: {}, + trendingMonthly: {}, categories: {}, allCategories: {}, searchTerm: '', + trendingRange: 'daily' } }, mounted() { this.fetchData(); this.fetchCategories(); + this.loadTrending(); + this.loadTrendingHashtags(); + this.loadTrendingPlaces(); }, methods: { @@ -130,6 +266,50 @@ if(this.searchTerm.length > 1) { window.location.href = '/i/results?q=' + this.searchTerm; } + }, + + loadTrending() { + if(this.trendingRange == 'daily' && this.trendingDaily.length) { + this.trending = this.trendingDaily; + return; + } + if(this.trendingRange == 'monthly' && this.trendingMonthly.length) { + this.trending = this.trendingMonthly; + return; + } + axios.get('/api/pixelfed/v2/discover/posts/trending', { + params: { + range: this.trendingRange + } + }) + .then(res => { + if(this.trendingRange == 'daily') { + this.trendingDaily = res.data; + } + if(this.trendingRange == 'monthly') { + this.trendingMonthly = res.data; + } + this.trending = res.data; + }); + }, + + trendingRangeToggle(r) { + this.trendingRange = r; + this.loadTrending(); + }, + + loadTrendingHashtags() { + axios.get('/api/pixelfed/v2/discover/posts/hashtags') + .then(res => { + this.hashtags = res.data; + }); + }, + + loadTrendingPlaces() { + axios.get('/api/pixelfed/v2/discover/posts/places') + .then(res => { + this.places = res.data; + }); } } } diff --git a/routes/web.php b/routes/web.php index 98d0993db..436d058fe 100644 --- a/routes/web.php +++ b/routes/web.php @@ -152,6 +152,9 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact Route::post('loops/watch', 'DiscoverController@loopWatch'); Route::get('discover/tag', 'DiscoverController@getHashtags'); Route::post('status/compose', 'InternalApiController@composePost')->middleware('throttle:maxPostsPerHour,60')->middleware('throttle:maxPostsPerDay,1440'); + Route::get('discover/posts/trending', 'DiscoverController@trendingApi'); + Route::get('discover/posts/hashtags', 'DiscoverController@trendingHashtags'); + Route::get('discover/posts/places', 'DiscoverController@trendingPlaces'); }); }); Route::group(['prefix' => 'local'], function () {