Explorar o código

Merge pull request #2599 from pixelfed/staging

Staging
daniel %!s(int64=4) %!d(string=hai) anos
pai
achega
8757476aff

+ 1 - 1
.env.docker

@@ -115,7 +115,7 @@ PF_COSTAR_ENABLED=false
 MEDIA_EXIF_DATABASE=false
 
 ## Logging
-LOG_CHANNEL=stack
+LOG_CHANNEL=stderr
 
 ## Image
 IMAGE_DRIVER=imagick

+ 13 - 1
CHANGELOG.md

@@ -6,7 +6,19 @@
 ### Updated
 - Updated AdminController, fix variable name in updateSpam method. ([6edaf940](https://github.com/pixelfed/pixelfed/commit/6edaf940))
 - Updated RemotAvatarFetch, only dispatch jobs if cloud storage is enabled. ([4f40f6f5](https://github.com/pixelfed/pixelfed/commit/4f40f6f5))
-
+- Updated StatusService, add ttl of 7 days. ([6e44ae0b](https://github.com/pixelfed/pixelfed/commit/6e44ae0b))
+- Updated StatusHashtagService, use StatusService for statuses. ([0355b567](https://github.com/pixelfed/pixelfed/commit/0355b567))
+- Updated StatusHashtagService, remove deprecated methods. ([aa4c718d](https://github.com/pixelfed/pixelfed/commit/aa4c718d))
+- Updated ApiV1Controller, add StatusService del calls to update likes_count, reblogs_count and reply_count. ([05b9445c](https://github.com/pixelfed/pixelfed/commit/05b9445c))
+- Updated Like, Status and Comment controllers to add StatusService del() method to update counts. ([eab4370c](https://github.com/pixelfed/pixelfed/commit/eab4370c))
+- Updated ComposeController, use placeholder image for video media. Fixes #2595. ([789ed4b4](https://github.com/pixelfed/pixelfed/commit/789ed4b4))
+- Updated DiscoverController, change api schema. ([2eea0409](https://github.com/pixelfed/pixelfed/commit/2eea0409))
+- Updated StatusDelete pipeline, call StatusService::del() to remove status from cache. ([3f772ff8](https://github.com/pixelfed/pixelfed/commit/3f772ff8))
+- Updated StatusHashtagTransformer, add blurhash attribute. ([899bbeba](https://github.com/pixelfed/pixelfed/commit/899bbeba))
+- Updated status square previews, add blurhash and improved content warnings. ([39e389dd](https://github.com/pixelfed/pixelfed/commit/39e389dd))
+- Updated Blurhash util, add default hash for invalid media. ([38a37c15](https://github.com/pixelfed/pixelfed/commit/38a37c15))
+- Updated VideoThumbnail job, generate blurhash for videos. ([896452c7](https://github.com/pixelfed/pixelfed/commit/896452c7))
+- Updated MediaTransformers, add default blurhash attribute. ([3f14a4c4](https://github.com/pixelfed/pixelfed/commit/3f14a4c4))
 
 ## [v0.10.10 (2021-01-28)](https://github.com/pixelfed/pixelfed/compare/v0.10.9...v0.10.10)
 ### Added

+ 6 - 0
app/Http/Controllers/Api/ApiV1Controller.php

@@ -50,6 +50,7 @@ use App\Services\{
     NotificationService,
     MediaPathService,
     SearchApiV2Service,
+    StatusService,
     MediaBlocklistService
 };
 
@@ -856,6 +857,8 @@ class ApiV1Controller extends Controller
             $status->save();
         }
 
+        StatusService::del($status->id);
+
         $resource = new Fractal\Resource\Item($status, new StatusTransformer());
         $res = $this->fractal->createData($resource)->toArray();
         return response()->json($res);
@@ -1766,6 +1769,7 @@ class ApiV1Controller extends Controller
             $status->in_reply_to_id = $parent->id;
             $status->in_reply_to_profile_id = $parent->profile_id;
             $status->save();
+            StatusService::del($parent->id);
         } else if($ids) {
             if(Media::whereUserId($user->id)
                 ->whereNull('status_id')
@@ -1883,6 +1887,7 @@ class ApiV1Controller extends Controller
             SharePipeline::dispatch($share);
         }
 
+        StatusService::del($status->id);
         $resource = new Fractal\Resource\Item($status, new StatusTransformer());
         $res = $this->fractal->createData($resource)->toArray();
         return response()->json($res);
@@ -1916,6 +1921,7 @@ class ApiV1Controller extends Controller
         $status->reblogs_count = $status->shares()->count();
         $status->save();
 
+        StatusService::del($status->id);
         $resource = new Fractal\Resource\Item($status, new StatusTransformer());
         $res = $this->fractal->createData($resource)->toArray();
         return response()->json($res);

+ 2 - 0
app/Http/Controllers/CommentController.php

@@ -18,6 +18,7 @@ use League\Fractal;
 use App\Transformer\Api\StatusTransformer;
 use League\Fractal\Serializer\ArraySerializer;
 use League\Fractal\Pagination\IlluminatePaginatorAdapter;
+use App\Services\StatusService;
 
 class CommentController extends Controller
 {
@@ -78,6 +79,7 @@ class CommentController extends Controller
             return $reply;
         });
 
+        StatusService::del($status->id);
         NewStatusPipeline::dispatch($reply, false);
         CommentPipeline::dispatch($status, $reply);
 

+ 6 - 6
app/Http/Controllers/ComposeController.php

@@ -39,6 +39,7 @@ use App\Services\NotificationService;
 use App\Services\MediaPathService;
 use App\Services\MediaBlocklistService;
 use App\Services\MediaTagService;
+use App\Services\ServiceService;
 use Illuminate\Support\Str;
 use App\Util\Lexer\Autolink;
 use App\Util\Lexer\Extractor;
@@ -117,10 +118,9 @@ class ComposeController extends Controller
 		$media->version = 3;
 		$media->save();
 
-		// $url = URL::temporarySignedRoute(
-		// 	'temp-media', now()->addHours(1), ['profileId' => $profile->id, 'mediaId' => $media->id, 'timestamp' => time()]
-		// );
-
+		$preview_url = $media->url() . '?v=' . time();
+		$url = $media->url() . '?v=' . time();
+		
 		switch ($media->mime) {
 			case 'image/jpeg':
 			case 'image/png':
@@ -139,8 +139,8 @@ class ComposeController extends Controller
 
 		$resource = new Fractal\Resource\Item($media, new MediaTransformer());
 		$res = $this->fractal->createData($resource)->toArray();
-		$res['preview_url'] = $media->url() . '?v=' . time();
-		$res['url'] = $media->url() . '?v=' . time();
+		$res['preview_url'] = $preview_url;
+		$res['url'] = $url;
 		return response()->json($res);
 	}
 

+ 8 - 2
app/Http/Controllers/DiscoverController.php

@@ -129,10 +129,16 @@ class DiscoverController extends Controller
       $tag = $request->input('hashtag');
 
       $hashtag = Hashtag::whereName($tag)->firstOrFail();
-      $res['tags'] = StatusHashtagService::get($hashtag->id, $page, $end);
       if($page == 1) {
-        $res['follows'] = HashtagFollow::whereUserId(Auth::id())->whereHashtagId($hashtag->id)->exists();
+        $res['follows'] = HashtagFollow::whereUserId(Auth::id())
+          ->whereHashtagId($hashtag->id)
+          ->exists();
       }
+      $res['hashtag'] = [
+        'name' => $hashtag->name,
+        'url' => $hashtag->url()
+      ];
+      $res['tags'] = StatusHashtagService::get($hashtag->id, $page, $end);
       return $res;
     }
 

+ 2 - 0
app/Http/Controllers/LikeController.php

@@ -9,6 +9,7 @@ use App\User;
 use Auth;
 use Cache;
 use Illuminate\Http\Request;
+use App\Services\StatusService;
 
 class LikeController extends Controller
 {
@@ -58,6 +59,7 @@ class LikeController extends Controller
         }
 
         Cache::forget('status:'.$status->id.':likedby:userid:'.$user->id);
+        StatusService::del($status->id);
 
         if ($request->ajax()) {
             $response = ['code' => 200, 'msg' => 'Like saved', 'count' => $count];

+ 4 - 1
app/Http/Controllers/StatusController.php

@@ -20,6 +20,7 @@ use League\Fractal;
 use App\Util\Media\Filter;
 use Illuminate\Support\Str;
 use App\Services\HashidService;
+use App\Services\StatusService;
 
 class StatusController extends Controller
 {
@@ -211,6 +212,7 @@ class StatusController extends Controller
 
         Cache::forget('_api:statuses:recent_9:' . $status->profile_id);
         Cache::forget('profile:status_count:' . $status->profile_id);
+        StatusService::del($status->id);
         if ($status->profile_id == $user->profile->id || $user->is_admin == true) {
             Cache::forget('profile:status_count:'.$status->profile_id);
             StatusDelete::dispatch($status);
@@ -266,7 +268,8 @@ class StatusController extends Controller
         }
  
         Cache::forget('status:'.$status->id.':sharedby:userid:'.$user->id);
-
+        StatusService::del($status->id);
+        
         if ($request->ajax()) {
             $response = ['code' => 200, 'msg' => 'Share saved', 'count' => $count];
         } else {

+ 3 - 0
app/Jobs/LikePipeline/LikePipeline.php

@@ -14,6 +14,7 @@ use App\Util\ActivityPub\Helpers;
 use League\Fractal;
 use League\Fractal\Serializer\ArraySerializer;
 use App\Transformer\ActivityPub\Verb\Like as LikeTransformer;
+use App\Services\StatusService;
 
 class LikePipeline implements ShouldQueue
 {
@@ -58,6 +59,8 @@ class LikePipeline implements ShouldQueue
             return;
         }
 
+        StatusService::del($status->id);
+
         if($status->url && $actor->domain == null) {
             return $this->remoteLikeDeliver();
         }

+ 2 - 0
app/Jobs/StatusPipeline/StatusDelete.php

@@ -25,6 +25,7 @@ use GuzzleHttp\Pool;
 use GuzzleHttp\Client;
 use GuzzleHttp\Promise;
 use App\Util\ActivityPub\HttpSignature;
+use App\Services\StatusService;
 
 class StatusDelete implements ShouldQueue
 {
@@ -59,6 +60,7 @@ class StatusDelete implements ShouldQueue
         $status = $this->status;
         $profile = $this->status->profile;
 
+        StatusService::del($status->id);
         $count = $profile->statuses()
         ->getQuery()
         ->whereIn('type', ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album'])

+ 7 - 0
app/Jobs/VideoPipeline/VideoThumbnail.php

@@ -13,6 +13,7 @@ use FFMpeg;
 use Storage;
 use App\Media;
 use App\Jobs\MediaPipeline\MediaStoragePipeline;
+use App\Util\Media\Blurhash;
 
 class VideoThumbnail implements ShouldQueue
 {
@@ -59,6 +60,12 @@ class VideoThumbnail implements ShouldQueue
             $media->thumbnail_path = $save;
             $media->save();
 
+            $blurhash = Blurhash::generate($media);
+            if($blurhash) {
+                $media->blurhash = $blurhash;
+                $media->save();
+            }
+
         } catch (Exception $e) {
             
         }

+ 7 - 13
app/Services/StatusHashtagService.php

@@ -16,6 +16,10 @@ class StatusHashtagService {
 
 	public static function get($id, $page = 1, $stop = 9)
 	{
+		if($page > 20) {
+			return [];
+		}
+
 		return StatusHashtag::whereHashtagId($id)
 			->whereStatusVisibility('public')
 			->whereHas('media')
@@ -47,12 +51,12 @@ class StatusHashtagService {
 
 	public static function set($key, $val)
 	{
-		return Redis::zadd(self::CACHE_KEY . $key, $val, $val);
+		return 1;
 	}
 
 	public static function del($key)
 	{
-		return Redis::zrem(self::CACHE_KEY . $key, $key);
+		return 1;
 	}
 
 	public static function count($id)
@@ -66,16 +70,6 @@ class StatusHashtagService {
 
 	public static function getStatus($statusId, $hashtagId)
 	{
-		return Cache::remember('pf:services:status-hashtag:post:'.$statusId.':hashtag:'.$hashtagId, now()->addMonths(3), function() use($statusId, $hashtagId) {
-			$statusHashtag = StatusHashtag::with('profile', 'status', 'hashtag')
-				->whereStatusVisibility('public')
-				->whereStatusId($statusId)
-				->whereHashtagId($hashtagId)
-				->first();
-			$fractal = new Fractal\Manager();
-			$fractal->setSerializer(new ArraySerializer());
-			$resource = new Fractal\Resource\Item($statusHashtag, new StatusHashtagTransformer());
-			return $fractal->createData($resource)->toArray();
-		});
+		return ['status' => StatusService::get($statusId)];
 	}
 }

+ 16 - 22
app/Services/StatusService.php

@@ -2,6 +2,7 @@
 
 namespace App\Services;
 
+use Illuminate\Support\Facades\Cache;
 use Illuminate\Support\Facades\Redis;
 use App\Status;
 //use App\Transformer\Api\v3\StatusTransformer;
@@ -15,34 +16,27 @@ class StatusService {
 
 	const CACHE_KEY = 'pf:services:status:';
 
-	public static function get($id)
-	{
-		return json_decode(Redis::get(self::CACHE_KEY . $id) ?? self::coldGet($id), true);
-	}
-
-	public static function coldGet($id)
+	public static function key($id)
 	{
-		$status = Status::whereScope('public')->findOrFail($id);
-		$fractal = new Fractal\Manager();
-		$fractal->setSerializer(new ArraySerializer());
-		$resource = new Fractal\Resource\Item($status, new StatusStatelessTransformer());
-		$res = $fractal->createData($resource)->toJson();
-		self::set($id, $res);
-		return $res;
+		return self::CACHE_KEY . $id;
 	}
 
-	public static function set($key, $val)
-	{
-		return Redis::set(self::CACHE_KEY . $key, $val);
-	}
-
-	public static function del($key)
+	public static function get($id)
 	{
-		return Redis::del(self::CACHE_KEY . $key);
+		return Cache::remember(self::key($id), now()->addDays(7), function() use($id) {
+			$status = Status::whereScope('public')->find($id);
+			if(!$status) {
+				return null;
+			}
+			$fractal = new Fractal\Manager();
+			$fractal->setSerializer(new ArraySerializer());
+			$resource = new Fractal\Resource\Item($status, new StatusStatelessTransformer());
+			return $fractal->createData($resource)->toArray();
+		});
 	}
 
-	public static function rem($key)
+	public static function del($id)
 	{
-		return self::del($key);
+		return Cache::forget(self::key($id));
 	}
 }

+ 1 - 1
app/Transformer/Api/Mastodon/v1/MediaTransformer.php

@@ -18,7 +18,7 @@ class MediaTransformer extends Fractal\TransformerAbstract
             'text_url'      => null,
             'meta'          => null,
             'description'   => $media->caption,
-            'blurhash'      => $media->blurhash
+            'blurhash'      => $media->blurhash ?? 'U4Rfzst8?bt7ogayj[j[~pfQ9Goe%Mj[WBay'
         ];
 
         if($media->width && $media->height) {

+ 1 - 1
app/Transformer/Api/MediaTransformer.php

@@ -24,7 +24,7 @@ class MediaTransformer extends Fractal\TransformerAbstract
             'filter_name'   => $media->filter_name,
             'filter_class'  => $media->version == 1 ? $media->filter_class : null,
             'mime'          => $media->mime,
-            'blurhash'      => $media->blurhash
+            'blurhash'      => $media->blurhash ?? 'U4Rfzst8?bt7ogayj[j[~pfQ9Goe%Mj[WBay'
         ];
 
         if($media->width && $media->height) {

+ 1 - 0
app/Transformer/Api/StatusHashtagTransformer.php

@@ -20,6 +20,7 @@ class StatusHashtagTransformer extends Fractal\TransformerAbstract
 				'url' 			=> $status->url(),
 				'thumb' 		=> $status->thumb(true),
 				'filter' 		=> $status->firstMedia()->filter_class,
+				'blurhash'		=> $status->firstMedia()->blurhash,
 				'sensitive' 	=> (bool) $status->is_nsfw,
 				'like_count' 	=> $status->likes_count,
 				'share_count' 	=> $status->reblogs_count,

+ 1 - 0
app/Transformer/Api/StatusStatelessTransformer.php

@@ -20,6 +20,7 @@ class StatusStatelessTransformer extends Fractal\TransformerAbstract
         $taggedPeople = MediaTagService::get($status->id);
 
         return [
+            '_v'                        => 1,
             'id'                        => (string) $status->id,
             'shortcode'                 => HashidService::encode($status->id),
             'uri'                       => $status->url(),

+ 1 - 0
app/Transformer/Api/StatusTransformer.php

@@ -22,6 +22,7 @@ class StatusTransformer extends Fractal\TransformerAbstract
         $taggedPeople = MediaTagService::get($status->id);
         
         return [
+            '_v'                        => 1,
             'id'                        => (string) $status->id,
             'shortcode'                 => HashidService::encode($status->id),
             'uri'                       => $status->url(),

+ 13 - 4
app/Util/Media/Blurhash.php

@@ -7,19 +7,28 @@ use App\Media;
 
 class Blurhash {
 
+	const DEFAULT_HASH = 'U4Rfzst8?bt7ogayj[j[~pfQ9Goe%Mj[WBay';
+
 	public static function generate(Media $media)
 	{
-		if(!in_array($media->mime, ['image/png', 'image/jpeg'])) {
-			return;
+		if(!in_array($media->mime, ['image/png', 'image/jpeg', 'video/mp4'])) {
+			return self::DEFAULT_HASH;
+		}
+
+		if($media->thumbnail_path == null) {
+			return self::DEFAULT_HASH;
 		}
 
 		$file  = storage_path('app/' . $media->thumbnail_path);
 
 		if(!is_file($file)) {
-			return;
+			return self::DEFAULT_HASH;
 		}
 
 		$image = imagecreatefromstring(file_get_contents($file));
+		if(!$image) {
+			return self::DEFAULT_HASH;
+		}
 		$width = imagesx($image);
 		$height = imagesy($image);
 
@@ -39,7 +48,7 @@ class Blurhash {
 		$components_y = 4;
 		$blurhash = BlurhashEngine::encode($pixels, $components_x, $components_y);
 		if(strlen($blurhash) > 191) {
-			return;
+			return self::DEFAULT_HASH;
 		}
 		return $blurhash;
 	}

BIN=BIN
public/css/app.css


BIN=BIN
public/css/appdark.css


BIN=BIN
public/css/landing.css


BIN=BIN
public/js/hashtag.js


BIN=BIN
public/js/profile.js


BIN=BIN
public/mix-manifest.json


+ 37 - 6
resources/assets/js/components/Hashtag.vue

@@ -36,8 +36,16 @@
 				<div v-for="(tag, index) in top" class="col-4 p-0 p-sm-2 p-md-3 hashtag-post-square">
 					<a class="card info-overlay card-md-border-0" :href="tag.status.url">
 						<div :class="[tag.status.filter ? 'square ' + tag.status.filter : 'square']">
-							<div v-if="tag.status.sensitive && forceNsfw == false" class="square-content" :style="'background-image: url(/storage/no-preview.png)'"></div>
-							<div v-else class="square-content" :style="'background-image: url('+tag.status.thumb+')'"></div>
+							<div v-if="tag.status.sensitive && forceNsfw == false" class="square-content">
+								<blur-hash-image
+									v-if="s.sensitive"
+									width="32"
+									height="32"
+									punch="1"
+									:hash="tag.status.media_attachments[0].blurhash"
+									/>
+							</div>
+							<div v-else class="square-content" :style="'background-image: url('+tag.status.media_attachments[0].preview_url+')'"></div>
 							<div class="info-overlay-text">
 								<h5 class="text-white m-auto font-weight-bold">
 									<span class="pr-4">
@@ -57,15 +65,38 @@
 				<div v-for="(tag, index) in tags" class="col-4 p-0 p-sm-2 p-md-3 hashtag-post-square">
 					<a class="card info-overlay card-md-border-0" :href="tag.status.url">
 						<div :class="[tag.status.filter ? 'square ' + tag.status.filter : 'square']">
-							<div v-if="tag.status.sensitive && forceNsfw == false" class="square-content" :style="'background-image: url(/storage/no-preview.png)'"></div>
-							<div v-else class="square-content" :style="'background-image: url('+tag.status.thumb+')'"></div>
+							<div v-if="tag.status.sensitive && forceNsfw == false" class="square-content">
+								<div class="info-overlay-text-label">
+									<h5 class="text-white m-auto font-weight-bold">
+										<span>
+											<span class="far fa-eye-slash fa-lg p-2 d-flex-inline"></span>
+										</span>
+									</h5>
+								</div>
+								<blur-hash-canvas
+									width="32"
+									height="32"
+									:hash="tag.status.media_attachments[0].blurhash"
+									/>
+							</div>
+							<div v-else class="square-content">
+								<blur-hash-image
+									width="32"
+									height="32"
+									:hash="tag.status.media_attachments[0].blurhash"
+									:src="tag.status.media_attachments[0].preview_url"
+									/>
+							</div>
+							<span v-if="tag.status.pf_type == 'photo:album'" class="float-right mr-3 post-icon"><i class="fas fa-images fa-2x"></i></span>
+							<span v-if="tag.status.pf_type == 'video'" class="float-right mr-3 post-icon"><i class="fas fa-video fa-2x"></i></span>
+							<span v-if="tag.status.pf_type == 'video:album'" class="float-right mr-3 post-icon"><i class="fas fa-film fa-2x"></i></span>
 							<div class="info-overlay-text">
 								<h5 class="text-white m-auto font-weight-bold">
 									<span class="pr-4">
-										<span class="far fa-heart fa-lg pr-1"></span> {{tag.status.like_count}}
+										<span class="far fa-heart fa-lg pr-1"></span> {{tag.status.favourites_count}}
 									</span>
 									<span>
-										<span class="fas fa-retweet fa-lg pr-1"></span> {{tag.status.share_count}}
+										<span class="far fa-comment fa-lg pr-1"></span> {{tag.status.reply_count}}
 									</span>
 								</h5>
 							</div>

+ 32 - 6
resources/assets/js/components/Profile.vue

@@ -183,21 +183,42 @@
 					<div class="row" v-if="mode == 'grid'">
 						<div class="col-4 p-1 p-md-3" v-for="(s, index) in timeline" :key="'tlob:'+index">
 							<a class="card info-overlay card-md-border-0" :href="statusUrl(s)" v-once>
-								<div :class="[s.sensitive ? 'square' : 'square ' + s.media_attachments[0].filter_class]">
+								<div class="square">
+									<div v-if="s.sensitive" class="square-content">
+										<div class="info-overlay-text-label">
+											<h5 class="text-white m-auto font-weight-bold">
+												<span>
+													<span class="far fa-eye-slash fa-lg p-2 d-flex-inline"></span>
+												</span>
+											</h5>
+										</div>
+										<blur-hash-canvas
+											width="32"
+											height="32"
+											:hash="s.media_attachments[0].blurhash"
+											/>
+									</div>
+									<div v-else class="square-content">
+										
+										<blur-hash-image
+											width="32"
+											height="32"
+											:hash="s.media_attachments[0].blurhash"
+											:src="s.media_attachments[0].preview_url"
+											/>
+									</div>
 									<span v-if="s.pf_type == 'photo:album'" class="float-right mr-3 post-icon"><i class="fas fa-images fa-2x"></i></span>
 									<span v-if="s.pf_type == 'video'" class="float-right mr-3 post-icon"><i class="fas fa-video fa-2x"></i></span>
 									<span v-if="s.pf_type == 'video:album'" class="float-right mr-3 post-icon"><i class="fas fa-film fa-2x"></i></span>
-									<div class="square-content" v-bind:style="previewBackground(s)">
-									</div>
 									<div class="info-overlay-text">
 										<h5 class="text-white m-auto font-weight-bold">
 											<span>
 												<span class="far fa-heart fa-lg p-2 d-flex-inline"></span>
-												<span class="d-flex-inline">{{s.favourites_count}}</span>
+												<span class="d-flex-inline">{{formatCount(s.favourites_count)}}</span>
 											</span>
 											<span>
-												<span class="fas fa-retweet fa-lg p-2 d-flex-inline"></span>
-												<span class="d-flex-inline">{{s.reblogs_count}}</span>
+												<span class="far fa-comment fa-lg p-2 d-flex-inline"></span>
+												<span class="d-flex-inline">{{formatCount(s.reply_count)}}</span>
 											</span>
 										</h5>
 									</div>
@@ -818,6 +839,11 @@
 				return 'background-image: url(' + preview + ');';
 			},
 
+			blurhHashMedia(status) {
+				return status.sensitive ? null :
+					status.media_attachments[0].preview_url;
+			},
+
 			switchMode(mode) {
 				this.mode = _.indexOf(this.modes, mode) ? mode : 'grid';
 				if(this.mode == 'bookmarks' && this.bookmarks.length == 0) {

+ 29 - 0
resources/assets/sass/custom.scss

@@ -131,6 +131,22 @@ body, button, input, textarea {
     background-color: rgba(0,0,0,0.5);
 }
 
+.info-overlay-text-label {
+    display: flex;
+    position: absolute;
+    width: 100%;
+    height: 100%;
+    background-color: rgba(0,0,0,0.5);
+
+    h5 {
+      z-index: 2;
+    }
+}
+
+.info-overlay:hover .info-overlay-text-label {
+    display: none;
+}
+
 .font-weight-lighter {
     font-weight: 300 !important
 }
@@ -565,4 +581,17 @@ details summary::-webkit-details-marker {
 
 .follow-modal {
   max-width: 400px !important;
+}
+
+.square-content {
+  img {
+    object-fit: cover !important;
+  }
+}
+
+.square .square-content {
+  canvas {
+    width: 100%;
+    height: 100%;
+  }
 }