Merge pull request #2599 from pixelfed/staging

Staging
pull/2607/head
daniel 4 years ago committed by GitHub
commit 8757476aff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -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%;
}
}
Loading…
Cancel
Save