Merge pull request #2599 from pixelfed/staging

Staging
This commit is contained in:
daniel 2021-01-30 17:39:04 -07:00 committed by GitHub
commit 8757476aff
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 195 additions and 66 deletions

View file

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

View file

@ -6,7 +6,19 @@
### Updated ### Updated
- Updated AdminController, fix variable name in updateSpam method. ([6edaf940](https://github.com/pixelfed/pixelfed/commit/6edaf940)) - 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 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) ## [v0.10.10 (2021-01-28)](https://github.com/pixelfed/pixelfed/compare/v0.10.9...v0.10.10)
### Added ### Added

View file

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

View file

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

View file

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

View file

@ -129,10 +129,16 @@ class DiscoverController extends Controller
$tag = $request->input('hashtag'); $tag = $request->input('hashtag');
$hashtag = Hashtag::whereName($tag)->firstOrFail(); $hashtag = Hashtag::whereName($tag)->firstOrFail();
$res['tags'] = StatusHashtagService::get($hashtag->id, $page, $end);
if($page == 1) { 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; return $res;
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -16,6 +16,10 @@ class StatusHashtagService {
public static function get($id, $page = 1, $stop = 9) public static function get($id, $page = 1, $stop = 9)
{ {
if($page > 20) {
return [];
}
return StatusHashtag::whereHashtagId($id) return StatusHashtag::whereHashtagId($id)
->whereStatusVisibility('public') ->whereStatusVisibility('public')
->whereHas('media') ->whereHas('media')
@ -47,12 +51,12 @@ class StatusHashtagService {
public static function set($key, $val) public static function set($key, $val)
{ {
return Redis::zadd(self::CACHE_KEY . $key, $val, $val); return 1;
} }
public static function del($key) public static function del($key)
{ {
return Redis::zrem(self::CACHE_KEY . $key, $key); return 1;
} }
public static function count($id) public static function count($id)
@ -66,16 +70,6 @@ class StatusHashtagService {
public static function getStatus($statusId, $hashtagId) public static function getStatus($statusId, $hashtagId)
{ {
return Cache::remember('pf:services:status-hashtag:post:'.$statusId.':hashtag:'.$hashtagId, now()->addMonths(3), function() use($statusId, $hashtagId) { return ['status' => StatusService::get($statusId)];
$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();
});
} }
} }

View file

@ -2,6 +2,7 @@
namespace App\Services; namespace App\Services;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Redis; use Illuminate\Support\Facades\Redis;
use App\Status; use App\Status;
//use App\Transformer\Api\v3\StatusTransformer; //use App\Transformer\Api\v3\StatusTransformer;
@ -15,34 +16,27 @@ class StatusService {
const CACHE_KEY = 'pf:services:status:'; const CACHE_KEY = 'pf:services:status:';
public static function key($id)
{
return self::CACHE_KEY . $id;
}
public static function get($id) public static function get($id)
{ {
return json_decode(Redis::get(self::CACHE_KEY . $id) ?? self::coldGet($id), true); 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 coldGet($id) public static function del($id)
{ {
$status = Status::whereScope('public')->findOrFail($id); return Cache::forget(self::key($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;
}
public static function set($key, $val)
{
return Redis::set(self::CACHE_KEY . $key, $val);
}
public static function del($key)
{
return Redis::del(self::CACHE_KEY . $key);
}
public static function rem($key)
{
return self::del($key);
} }
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

BIN
public/css/app.css vendored

Binary file not shown.

BIN
public/css/appdark.css vendored

Binary file not shown.

BIN
public/css/landing.css vendored

Binary file not shown.

BIN
public/js/hashtag.js vendored

Binary file not shown.

BIN
public/js/profile.js vendored

Binary file not shown.

Binary file not shown.

View file

@ -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"> <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"> <a class="card info-overlay card-md-border-0" :href="tag.status.url">
<div :class="[tag.status.filter ? 'square ' + tag.status.filter : 'square']"> <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-if="tag.status.sensitive && forceNsfw == false" class="square-content">
<div v-else class="square-content" :style="'background-image: url('+tag.status.thumb+')'"></div> <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"> <div class="info-overlay-text">
<h5 class="text-white m-auto font-weight-bold"> <h5 class="text-white m-auto font-weight-bold">
<span class="pr-4"> <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"> <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"> <a class="card info-overlay card-md-border-0" :href="tag.status.url">
<div :class="[tag.status.filter ? 'square ' + tag.status.filter : 'square']"> <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-if="tag.status.sensitive && forceNsfw == false" class="square-content">
<div v-else class="square-content" :style="'background-image: url('+tag.status.thumb+')'"></div> <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"> <div class="info-overlay-text">
<h5 class="text-white m-auto font-weight-bold"> <h5 class="text-white m-auto font-weight-bold">
<span class="pr-4"> <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> <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> </span>
</h5> </h5>
</div> </div>

View file

@ -183,21 +183,42 @@
<div class="row" v-if="mode == 'grid'"> <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"> <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> <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 == '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'" 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> <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"> <div class="info-overlay-text">
<h5 class="text-white m-auto font-weight-bold"> <h5 class="text-white m-auto font-weight-bold">
<span> <span>
<span class="far fa-heart fa-lg p-2 d-flex-inline"></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> <span>
<span class="fas fa-retweet fa-lg p-2 d-flex-inline"></span> <span class="far fa-comment fa-lg p-2 d-flex-inline"></span>
<span class="d-flex-inline">{{s.reblogs_count}}</span> <span class="d-flex-inline">{{formatCount(s.reply_count)}}</span>
</span> </span>
</h5> </h5>
</div> </div>
@ -818,6 +839,11 @@
return 'background-image: url(' + preview + ');'; return 'background-image: url(' + preview + ');';
}, },
blurhHashMedia(status) {
return status.sensitive ? null :
status.media_attachments[0].preview_url;
},
switchMode(mode) { switchMode(mode) {
this.mode = _.indexOf(this.modes, mode) ? mode : 'grid'; this.mode = _.indexOf(this.modes, mode) ? mode : 'grid';
if(this.mode == 'bookmarks' && this.bookmarks.length == 0) { if(this.mode == 'bookmarks' && this.bookmarks.length == 0) {

View file

@ -131,6 +131,22 @@ body, button, input, textarea {
background-color: rgba(0,0,0,0.5); 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-lighter {
font-weight: 300 !important font-weight: 300 !important
} }
@ -565,4 +581,17 @@ details summary::-webkit-details-marker {
.follow-modal { .follow-modal {
max-width: 400px !important; max-width: 400px !important;
}
.square-content {
img {
object-fit: cover !important;
}
}
.square .square-content {
canvas {
width: 100%;
height: 100%;
}
} }