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 205 additions and 76 deletions

View file

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

View file

@ -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

View file

@ -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);

View file

@ -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);

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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];

View file

@ -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 {

View file

@ -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();
}

View file

@ -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'])

View file

@ -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) {
}

View file

@ -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)];
}
}

View file

@ -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 key($id)
{
return self::CACHE_KEY . $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);
$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);
return Cache::forget(self::key($id));
}
}

View file

@ -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) {

View file

@ -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) {

View file

@ -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,

View file

@ -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(),

View file

@ -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(),

View file

@ -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;
}

2
public/css/app.css vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -4,9 +4,9 @@
"/js/ace.js": "/js/ace.js?id=11e5550a450fece75c33",
"/js/activity.js": "/js/activity.js?id=85479715e399b3489d25",
"/js/app.js": "/js/app.js?id=fdbdd51482b98e1324e8",
"/css/app.css": "/css/app.css?id=77729cabd5c8a0ad09b8",
"/css/appdark.css": "/css/appdark.css?id=995ec87dd4aff426cd1c",
"/css/landing.css": "/css/landing.css?id=3092e86721fa8b922c06",
"/css/app.css": "/css/app.css?id=d2e819a5e9bd647af865",
"/css/appdark.css": "/css/appdark.css?id=098ef0805c5b9b06ab9e",
"/css/landing.css": "/css/landing.css?id=b1672d4780c21672f548",
"/css/quill.css": "/css/quill.css?id=e3741782d15a3031f785",
"/js/collectioncompose.js": "/js/collectioncompose.js?id=c6a07cb79dd7d6c7b8a0",
"/js/collections.js": "/js/collections.js?id=6f64a9032085ebac28b3",
@ -16,12 +16,12 @@
"/js/developers.js": "/js/developers.js?id=f75deca5ccf47d43eb07",
"/js/direct.js": "/js/direct.js?id=e1e4a830bfedc1870db1",
"/js/discover.js": "/js/discover.js?id=87071f23fc6d7118c66a",
"/js/hashtag.js": "/js/hashtag.js?id=4ebd78fde7fe65f5772c",
"/js/hashtag.js": "/js/hashtag.js?id=f22994116815f17a4ad0",
"/js/loops.js": "/js/loops.js?id=1dcb3790eb9ea4ea5848",
"/js/memoryprofile.js": "/js/memoryprofile.js?id=75ea0503eca4f7ad3642",
"/js/mode-dot.js": "/js/mode-dot.js?id=dd9c87024fbaa8e75ac4",
"/js/my2020.js": "/js/my2020.js?id=31aeb1c22e0a5a99b0a8",
"/js/profile.js": "/js/profile.js?id=2e251656c84e1c283582",
"/js/profile.js": "/js/profile.js?id=a1f66841d7ff4e5fb737",
"/js/profile-directory.js": "/js/profile-directory.js?id=2386392b464e9088a859",
"/js/quill.js": "/js/quill.js?id=4769f11fc9a6c32dde50",
"/js/rempos.js": "/js/rempos.js?id=f4325d9c7ee4b5165a00",

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">
<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>

View file

@ -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) {

View file

@ -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%;
}
}