mirror of https://github.com/pixelfed/pixelfed.git
commit
ae38f2d8a6
|
@ -2,6 +2,9 @@
|
|||
|
||||
## [Unreleased](https://github.com/pixelfed/pixelfed/compare/v0.11.7...dev)
|
||||
|
||||
### Added
|
||||
- Post edits ([#4416](https://github.com/pixelfed/pixelfed/pull/4416)) ([98cf8f3](https://github.com/pixelfed/pixelfed/commit/98cf8f3))
|
||||
|
||||
### Updates
|
||||
- Update StatusService, fix bug in getFull method ([4d8b4dcf](https://github.com/pixelfed/pixelfed/commit/4d8b4dcf))
|
||||
- ([](https://github.com/pixelfed/pixelfed/commit/))
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Requests\Status\StoreStatusEditRequest;
|
||||
use App\Status;
|
||||
use App\Models\StatusEdit;
|
||||
use Purify;
|
||||
use App\Services\Status\UpdateStatusService;
|
||||
use App\Services\StatusService;
|
||||
use App\Util\Lexer\Autolink;
|
||||
use App\Jobs\StatusPipeline\StatusLocalUpdateActivityPubDeliverPipeline;
|
||||
|
||||
class StatusEditController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth');
|
||||
abort_if(!config('exp.pue'), 404, 'Post editing is not enabled on this server.');
|
||||
}
|
||||
|
||||
public function store(StoreStatusEditRequest $request, $id)
|
||||
{
|
||||
$validated = $request->validated();
|
||||
|
||||
$status = Status::findOrFail($id);
|
||||
abort_if(StatusEdit::whereStatusId($status->id)->count() >= 10, 400, 'You cannot edit your post more than 10 times.');
|
||||
$res = UpdateStatusService::call($status, $validated);
|
||||
|
||||
$status = Status::findOrFail($id);
|
||||
StatusLocalUpdateActivityPubDeliverPipeline::dispatch($status)->delay(now()->addMinutes(1));
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function history(Request $request, $id)
|
||||
{
|
||||
abort_if(!$request->user(), 403);
|
||||
$status = Status::whereNull('reblog_of_id')->findOrFail($id);
|
||||
abort_if(!in_array($status->scope, ['public', 'unlisted']), 403);
|
||||
if(!$status->edits()->count()) {
|
||||
return [];
|
||||
}
|
||||
$cached = StatusService::get($status->id, false);
|
||||
|
||||
$res = $status->edits->map(function($edit) use($cached) {
|
||||
return [
|
||||
'content' => Autolink::create()->autolink($edit->caption),
|
||||
'spoiler_text' => $edit->spoiler_text,
|
||||
'sensitive' => (bool) $edit->is_nsfw,
|
||||
'created_at' => str_replace('+00:00', 'Z', $edit->created_at->format(DATE_RFC3339_EXTENDED)),
|
||||
'account' => $cached['account'],
|
||||
'media_attachments' => $cached['media_attachments'],
|
||||
'emojis' => $cached['emojis'],
|
||||
];
|
||||
})->reverse()->values()->toArray();
|
||||
return $res;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests\Status;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use App\Media;
|
||||
use App\Status;
|
||||
use Closure;
|
||||
|
||||
class StoreStatusEditRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
$profile = $this->user()->profile;
|
||||
if($profile->status != null) {
|
||||
return false;
|
||||
}
|
||||
if($profile->unlisted == true && $profile->cw == true) {
|
||||
return false;
|
||||
}
|
||||
$types = [
|
||||
"photo",
|
||||
"photo:album",
|
||||
"photo:video:album",
|
||||
"reply",
|
||||
"text",
|
||||
"video",
|
||||
"video:album"
|
||||
];
|
||||
$scopes = ['public', 'unlisted', 'private'];
|
||||
$status = Status::whereNull('reblog_of_id')->whereIn('type', $types)->whereIn('scope', $scopes)->find($this->route('id'));
|
||||
return $status && $this->user()->profile_id === $status->profile_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'status' => 'sometimes|max:'.config('pixelfed.max_caption_length', 500),
|
||||
'spoiler_text' => 'nullable|string|max:140',
|
||||
'sensitive' => 'sometimes|boolean',
|
||||
'media_ids' => [
|
||||
'nullable',
|
||||
'required_without:status',
|
||||
'array',
|
||||
'max:' . config('pixelfed.max_album_length'),
|
||||
function (string $attribute, mixed $value, Closure $fail) {
|
||||
Media::whereProfileId($this->user()->profile_id)
|
||||
->where(function($query) {
|
||||
return $query->whereNull('status_id')
|
||||
->orWhere('status_id', '=', $this->route('id'));
|
||||
})
|
||||
->findOrFail($value);
|
||||
},
|
||||
],
|
||||
'location' => 'sometimes|nullable',
|
||||
'location.id' => 'sometimes|integer|min:1|max:128769',
|
||||
'location.country' => 'required_with:location.id',
|
||||
'location.name' => 'required_with:location.id',
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
<?php
|
||||
|
||||
namespace App\Jobs\StatusPipeline;
|
||||
|
||||
use Cache, Log;
|
||||
use App\Status;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use League\Fractal;
|
||||
use League\Fractal\Serializer\ArraySerializer;
|
||||
use App\Transformer\ActivityPub\Verb\UpdateNote;
|
||||
use App\Util\ActivityPub\Helpers;
|
||||
use GuzzleHttp\Pool;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Promise;
|
||||
use App\Util\ActivityPub\HttpSignature;
|
||||
|
||||
class StatusLocalUpdateActivityPubDeliverPipeline implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
protected $status;
|
||||
|
||||
/**
|
||||
* Delete the job if its models no longer exist.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $deleteWhenMissingModels = true;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Status $status)
|
||||
{
|
||||
$this->status = $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$status = $this->status;
|
||||
$profile = $status->profile;
|
||||
|
||||
// ignore group posts
|
||||
// if($status->group_id != null) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
if($status->local == false || $status->url || $status->uri) {
|
||||
return;
|
||||
}
|
||||
|
||||
$audience = $status->profile->getAudienceInbox();
|
||||
|
||||
if(empty($audience) || !in_array($status->scope, ['public', 'unlisted', 'private'])) {
|
||||
// Return on profiles with no remote followers
|
||||
return;
|
||||
}
|
||||
|
||||
switch($status->type) {
|
||||
case 'poll':
|
||||
// Polls not yet supported
|
||||
return;
|
||||
break;
|
||||
|
||||
default:
|
||||
$activitypubObject = new UpdateNote();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
$fractal = new Fractal\Manager();
|
||||
$fractal->setSerializer(new ArraySerializer());
|
||||
$resource = new Fractal\Resource\Item($status, $activitypubObject);
|
||||
$activity = $fractal->createData($resource)->toArray();
|
||||
|
||||
$payload = json_encode($activity);
|
||||
|
||||
$client = new Client([
|
||||
'timeout' => config('federation.activitypub.delivery.timeout')
|
||||
]);
|
||||
|
||||
$version = config('pixelfed.version');
|
||||
$appUrl = config('app.url');
|
||||
$userAgent = "(Pixelfed/{$version}; +{$appUrl})";
|
||||
|
||||
$requests = function($audience) use ($client, $activity, $profile, $payload, $userAgent) {
|
||||
foreach($audience as $url) {
|
||||
$headers = HttpSignature::sign($profile, $url, $activity, [
|
||||
'Content-Type' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
|
||||
'User-Agent' => $userAgent,
|
||||
]);
|
||||
yield function() use ($client, $url, $headers, $payload) {
|
||||
return $client->postAsync($url, [
|
||||
'curl' => [
|
||||
CURLOPT_HTTPHEADER => $headers,
|
||||
CURLOPT_POSTFIELDS => $payload,
|
||||
CURLOPT_HEADER => true,
|
||||
CURLOPT_SSL_VERIFYPEER => false,
|
||||
CURLOPT_SSL_VERIFYHOST => false
|
||||
]
|
||||
]);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
$pool = new Pool($client, $requests($audience), [
|
||||
'concurrency' => config('federation.activitypub.delivery.concurrency'),
|
||||
'fulfilled' => function ($response, $index) {
|
||||
},
|
||||
'rejected' => function ($reason, $index) {
|
||||
}
|
||||
]);
|
||||
|
||||
$promise = $pool->promise();
|
||||
|
||||
$promise->wait();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
<?php
|
||||
|
||||
namespace App\Jobs\StatusPipeline;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use App\Media;
|
||||
use App\ModLog;
|
||||
use App\Profile;
|
||||
use App\Status;
|
||||
use App\Models\StatusEdit;
|
||||
use App\Services\StatusService;
|
||||
use Purify;
|
||||
|
||||
class StatusRemoteUpdatePipeline implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public $activity;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*/
|
||||
public function __construct($activity)
|
||||
{
|
||||
$this->activity = $activity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
$activity = $this->activity;
|
||||
$status = Status::with('media')->whereObjectUrl($activity['id'])->first();
|
||||
if(!$status) {
|
||||
return;
|
||||
}
|
||||
$this->createPreviousEdit($status);
|
||||
$this->updateMedia($status, $activity);
|
||||
$this->updateImmediateAttributes($status, $activity);
|
||||
$this->createEdit($status, $activity);
|
||||
}
|
||||
|
||||
protected function createPreviousEdit($status)
|
||||
{
|
||||
if(!$status->edits()->count()) {
|
||||
StatusEdit::create([
|
||||
'status_id' => $status->id,
|
||||
'profile_id' => $status->profile_id,
|
||||
'caption' => $status->caption,
|
||||
'spoiler_text' => $status->cw_summary,
|
||||
'is_nsfw' => $status->is_nsfw,
|
||||
'ordered_media_attachment_ids' => $status->media()->orderBy('order')->pluck('id')->toArray(),
|
||||
'created_at' => $status->created_at
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
protected function updateMedia($status, $activity)
|
||||
{
|
||||
if(!isset($activity['attachment'])) {
|
||||
return;
|
||||
}
|
||||
$ogm = $status->media->count() ? $status->media()->orderBy('order')->get() : collect([]);
|
||||
$nm = collect($activity['attachment'])->filter(function($nm) {
|
||||
return isset(
|
||||
$nm['type'],
|
||||
$nm['mediaType'],
|
||||
$nm['url']
|
||||
) &&
|
||||
in_array($nm['type'], ['Document', 'Image', 'Video']) &&
|
||||
in_array($nm['mediaType'], explode(',', config('pixelfed.media_types')));
|
||||
});
|
||||
|
||||
// Skip when no media
|
||||
if(!$ogm->count() && !$nm->count()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Media::whereProfileId($status->profile_id)
|
||||
->whereStatusId($status->id)
|
||||
->update([
|
||||
'status_id' => null
|
||||
]);
|
||||
|
||||
$nm->each(function($n, $key) use($status) {
|
||||
$m = new Media;
|
||||
$m->status_id = $status->id;
|
||||
$m->profile_id = $status->profile_id;
|
||||
$m->remote_media = true;
|
||||
$m->media_path = $n['url'];
|
||||
$m->caption = isset($n['name']) && !empty($n['name']) ? Purify::clean($n['name']) : null;
|
||||
$m->remote_url = $n['url'];
|
||||
$m->width = isset($n['width']) && !empty($n['width']) ? $n['width'] : null;
|
||||
$m->height = isset($n['height']) && !empty($n['height']) ? $n['height'] : null;
|
||||
$m->skip_optimize = true;
|
||||
$m->order = $key + 1;
|
||||
$m->save();
|
||||
});
|
||||
}
|
||||
|
||||
protected function updateImmediateAttributes($status, $activity)
|
||||
{
|
||||
if(isset($activity['content'])) {
|
||||
$status->caption = strip_tags($activity['content']);
|
||||
$status->rendered = Purify::clean($activity['content']);
|
||||
}
|
||||
|
||||
if(isset($activity['sensitive'])) {
|
||||
if((bool) $activity['sensitive'] == false) {
|
||||
$status->is_nsfw = false;
|
||||
$exists = ModLog::whereObjectType('App\Status::class')
|
||||
->whereObjectId($status->id)
|
||||
->whereAction('admin.status.moderate')
|
||||
->exists();
|
||||
if($exists == true) {
|
||||
$status->is_nsfw = true;
|
||||
}
|
||||
$profile = Profile::find($status->profile_id);
|
||||
if(!$profile || $profile->cw == true) {
|
||||
$status->is_nsfw = true;
|
||||
}
|
||||
} else {
|
||||
$status->is_nsfw = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($activity['summary'])) {
|
||||
$status->cw_summary = Purify::clean($activity['summary']);
|
||||
} else {
|
||||
$status->cw_summary = null;
|
||||
}
|
||||
|
||||
$status->edited_at = now();
|
||||
$status->save();
|
||||
StatusService::del($status->id);
|
||||
}
|
||||
|
||||
protected function createEdit($status, $activity)
|
||||
{
|
||||
$cleaned = isset($activity['content']) ? Purify::clean($activity['content']) : null;
|
||||
$spoiler_text = isset($activity['summary']) ? Purify::clean($attributes['summary']) : null;
|
||||
$sensitive = isset($activity['sensitive']) ? $activity['sensitive'] : null;
|
||||
$mids = $status->media()->count() ? $status->media()->orderBy('order')->pluck('id')->toArray() : null;
|
||||
StatusEdit::create([
|
||||
'status_id' => $status->id,
|
||||
'profile_id' => $status->profile_id,
|
||||
'caption' => $cleaned,
|
||||
'spoiler_text' => $spoiler_text,
|
||||
'is_nsfw' => $sensitive,
|
||||
'ordered_media_attachment_ids' => $mids
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class StatusEdit extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $casts = [
|
||||
'ordered_media_attachment_ids' => 'array',
|
||||
'media_descriptions' => 'array',
|
||||
'poll_options' => 'array'
|
||||
];
|
||||
|
||||
protected $guarded = [];
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services\Status;
|
||||
|
||||
use App\Media;
|
||||
use App\ModLog;
|
||||
use App\Status;
|
||||
use App\Models\StatusEdit;
|
||||
use Purify;
|
||||
use App\Util\Lexer\Autolink;
|
||||
use App\Services\MediaService;
|
||||
use App\Services\MediaStorageService;
|
||||
use App\Services\StatusService;
|
||||
|
||||
class UpdateStatusService
|
||||
{
|
||||
public static function call(Status $status, $attributes)
|
||||
{
|
||||
self::createPreviousEdit($status);
|
||||
self::updateMediaAttachements($status, $attributes);
|
||||
self::handleImmediateAttributes($status, $attributes);
|
||||
self::createEdit($status, $attributes);
|
||||
|
||||
return StatusService::get($status->id);
|
||||
}
|
||||
|
||||
public static function updateMediaAttachements(Status $status, $attributes)
|
||||
{
|
||||
$count = $status->media()->count();
|
||||
if($count === 0 || $count === 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
$oids = $status->media()->orderBy('order')->pluck('id')->map(function($m) { return (string) $m; });
|
||||
$nids = collect($attributes['media_ids']);
|
||||
|
||||
if($oids->toArray() === $nids->toArray()) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach($oids->diff($nids)->values()->toArray() as $mid) {
|
||||
$media = Media::find($mid);
|
||||
if(!$media) {
|
||||
continue;
|
||||
}
|
||||
$media->status_id = null;
|
||||
$media->save();
|
||||
MediaStorageService::delete($media, true);
|
||||
}
|
||||
|
||||
$nids->each(function($nid, $idx) {
|
||||
$media = Media::find($nid);
|
||||
if(!$media) {
|
||||
return;
|
||||
}
|
||||
$media->order = $idx;
|
||||
$media->save();
|
||||
});
|
||||
MediaService::del($status->id);
|
||||
}
|
||||
|
||||
public static function handleImmediateAttributes(Status $status, $attributes)
|
||||
{
|
||||
if(isset($attributes['status'])) {
|
||||
$cleaned = Purify::clean($attributes['status']);
|
||||
$status->caption = $cleaned;
|
||||
$status->rendered = Autolink::create()->autolink($cleaned);
|
||||
} else {
|
||||
$status->caption = null;
|
||||
$status->rendered = null;
|
||||
}
|
||||
if(isset($attributes['sensitive'])) {
|
||||
if($status->is_nsfw != (bool) $attributes['sensitive'] &&
|
||||
(bool) $attributes['sensitive'] == false)
|
||||
{
|
||||
$exists = ModLog::whereObjectType('App\Status::class')
|
||||
->whereObjectId($status->id)
|
||||
->whereAction('admin.status.moderate')
|
||||
->exists();
|
||||
if(!$exists) {
|
||||
$status->is_nsfw = (bool) $attributes['sensitive'];
|
||||
}
|
||||
} else {
|
||||
$status->is_nsfw = (bool) $attributes['sensitive'];
|
||||
}
|
||||
}
|
||||
if(isset($attributes['spoiler_text'])) {
|
||||
$status->cw_summary = Purify::clean($attributes['spoiler_text']);
|
||||
} else {
|
||||
$status->cw_summary = null;
|
||||
}
|
||||
if(isset($attributes['location'])) {
|
||||
if (isset($attributes['location']['id'])) {
|
||||
$status->place_id = $attributes['location']['id'];
|
||||
} else {
|
||||
$status->place_id = null;
|
||||
}
|
||||
}
|
||||
if($status->cw_summary && !$status->is_nsfw) {
|
||||
$status->cw_summary = null;
|
||||
}
|
||||
$status->edited_at = now();
|
||||
$status->save();
|
||||
StatusService::del($status->id);
|
||||
}
|
||||
|
||||
public static function createPreviousEdit(Status $status)
|
||||
{
|
||||
if(!$status->edits()->count()) {
|
||||
StatusEdit::create([
|
||||
'status_id' => $status->id,
|
||||
'profile_id' => $status->profile_id,
|
||||
'caption' => $status->caption,
|
||||
'spoiler_text' => $status->cw_summary,
|
||||
'is_nsfw' => $status->is_nsfw,
|
||||
'ordered_media_attachment_ids' => $status->media()->orderBy('order')->pluck('id')->toArray(),
|
||||
'created_at' => $status->created_at
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public static function createEdit(Status $status, $attributes)
|
||||
{
|
||||
$cleaned = isset($attributes['status']) ? Purify::clean($attributes['status']) : null;
|
||||
$spoiler_text = isset($attributes['spoiler_text']) ? Purify::clean($attributes['spoiler_text']) : null;
|
||||
$sensitive = isset($attributes['sensitive']) ? $attributes['sensitive'] : null;
|
||||
$mids = $status->media()->count() ? $status->media()->orderBy('order')->pluck('id')->toArray() : null;
|
||||
StatusEdit::create([
|
||||
'status_id' => $status->id,
|
||||
'profile_id' => $status->profile_id,
|
||||
'caption' => $cleaned,
|
||||
'spoiler_text' => $spoiler_text,
|
||||
'is_nsfw' => $sensitive,
|
||||
'ordered_media_attachment_ids' => $mids
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ use App\Http\Controllers\StatusController;
|
|||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use App\Models\Poll;
|
||||
use App\Services\AccountService;
|
||||
use App\Models\StatusEdit;
|
||||
|
||||
class Status extends Model
|
||||
{
|
||||
|
@ -27,7 +28,8 @@ class Status extends Model
|
|||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'deleted_at' => 'datetime'
|
||||
'deleted_at' => 'datetime',
|
||||
'edited_at' => 'datetime'
|
||||
];
|
||||
|
||||
protected $guarded = [];
|
||||
|
@ -393,4 +395,9 @@ class Status extends Model
|
|||
{
|
||||
return $this->hasOne(Poll::class);
|
||||
}
|
||||
|
||||
public function edits()
|
||||
{
|
||||
return $this->hasMany(StatusEdit::class);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
<?php
|
||||
|
||||
namespace App\Transformer\ActivityPub\Verb;
|
||||
|
||||
use App\Status;
|
||||
use League\Fractal;
|
||||
use App\Models\CustomEmoji;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class UpdateNote extends Fractal\TransformerAbstract
|
||||
{
|
||||
public function transform(Status $status)
|
||||
{
|
||||
$mentions = $status->mentions->map(function ($mention) {
|
||||
$webfinger = $mention->emailUrl();
|
||||
$name = Str::startsWith($webfinger, '@') ?
|
||||
$webfinger :
|
||||
'@' . $webfinger;
|
||||
return [
|
||||
'type' => 'Mention',
|
||||
'href' => $mention->permalink(),
|
||||
'name' => $name
|
||||
];
|
||||
})->toArray();
|
||||
|
||||
if($status->in_reply_to_id != null) {
|
||||
$parent = $status->parent()->profile;
|
||||
if($parent) {
|
||||
$webfinger = $parent->emailUrl();
|
||||
$name = Str::startsWith($webfinger, '@') ?
|
||||
$webfinger :
|
||||
'@' . $webfinger;
|
||||
$reply = [
|
||||
'type' => 'Mention',
|
||||
'href' => $parent->permalink(),
|
||||
'name' => $name
|
||||
];
|
||||
$mentions = array_merge($reply, $mentions);
|
||||
}
|
||||
}
|
||||
|
||||
$hashtags = $status->hashtags->map(function ($hashtag) {
|
||||
return [
|
||||
'type' => 'Hashtag',
|
||||
'href' => $hashtag->url(),
|
||||
'name' => "#{$hashtag->name}",
|
||||
];
|
||||
})->toArray();
|
||||
|
||||
$emojis = CustomEmoji::scan($status->caption, true) ?? [];
|
||||
$emoji = array_merge($emojis, $mentions);
|
||||
$tags = array_merge($emoji, $hashtags);
|
||||
|
||||
$latestEdit = $status->edits()->latest()->first();
|
||||
|
||||
return [
|
||||
'@context' => [
|
||||
'https://w3id.org/security/v1',
|
||||
'https://www.w3.org/ns/activitystreams',
|
||||
[
|
||||
'Hashtag' => 'as:Hashtag',
|
||||
'sensitive' => 'as:sensitive',
|
||||
'schema' => 'http://schema.org/',
|
||||
'pixelfed' => 'http://pixelfed.org/ns#',
|
||||
'commentsEnabled' => [
|
||||
'@id' => 'pixelfed:commentsEnabled',
|
||||
'@type' => 'schema:Boolean'
|
||||
],
|
||||
'capabilities' => [
|
||||
'@id' => 'pixelfed:capabilities',
|
||||
'@container' => '@set'
|
||||
],
|
||||
'announce' => [
|
||||
'@id' => 'pixelfed:canAnnounce',
|
||||
'@type' => '@id'
|
||||
],
|
||||
'like' => [
|
||||
'@id' => 'pixelfed:canLike',
|
||||
'@type' => '@id'
|
||||
],
|
||||
'reply' => [
|
||||
'@id' => 'pixelfed:canReply',
|
||||
'@type' => '@id'
|
||||
],
|
||||
'toot' => 'http://joinmastodon.org/ns#',
|
||||
'Emoji' => 'toot:Emoji'
|
||||
]
|
||||
],
|
||||
'id' => $status->permalink('#updates/' . $latestEdit->id),
|
||||
'type' => 'Update',
|
||||
'actor' => $status->profile->permalink(),
|
||||
'published' => $latestEdit->created_at->toAtomString(),
|
||||
'to' => $status->scopeToAudience('to'),
|
||||
'cc' => $status->scopeToAudience('cc'),
|
||||
'object' => [
|
||||
'id' => $status->url(),
|
||||
'type' => 'Note',
|
||||
'summary' => $status->is_nsfw ? $status->cw_summary : null,
|
||||
'content' => $status->rendered ?? $status->caption,
|
||||
'inReplyTo' => $status->in_reply_to_id ? $status->parent()->url() : null,
|
||||
'published' => $status->created_at->toAtomString(),
|
||||
'url' => $status->url(),
|
||||
'attributedTo' => $status->profile->permalink(),
|
||||
'to' => $status->scopeToAudience('to'),
|
||||
'cc' => $status->scopeToAudience('cc'),
|
||||
'sensitive' => (bool) $status->is_nsfw,
|
||||
'attachment' => $status->media()->orderBy('order')->get()->map(function ($media) {
|
||||
return [
|
||||
'type' => $media->activityVerb(),
|
||||
'mediaType' => $media->mime,
|
||||
'url' => $media->url(),
|
||||
'name' => $media->caption,
|
||||
];
|
||||
})->toArray(),
|
||||
'tag' => $tags,
|
||||
'commentsEnabled' => (bool) !$status->comments_disabled,
|
||||
'updated' => $latestEdit->created_at->toAtomString(),
|
||||
'capabilities' => [
|
||||
'announce' => 'https://www.w3.org/ns/activitystreams#Public',
|
||||
'like' => 'https://www.w3.org/ns/activitystreams#Public',
|
||||
'reply' => $status->comments_disabled == true ? '[]' : 'https://www.w3.org/ns/activitystreams#Public'
|
||||
],
|
||||
'location' => $status->place_id ? [
|
||||
'type' => 'Place',
|
||||
'name' => $status->place->name,
|
||||
'longitude' => $status->place->long,
|
||||
'latitude' => $status->place->lat,
|
||||
'country' => $status->place->country
|
||||
] : null,
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
|
@ -65,7 +65,8 @@ class StatusStatelessTransformer extends Fractal\TransformerAbstract
|
|||
'media_attachments' => MediaService::get($status->id),
|
||||
'account' => AccountService::get($status->profile_id, true),
|
||||
'tags' => StatusHashtagService::statusTags($status->id),
|
||||
'poll' => $poll
|
||||
'poll' => $poll,
|
||||
'edited_at' => $status->edited_at ? str_replace('+00:00', 'Z', $status->edited_at->format(DATE_RFC3339_EXTENDED)) : null,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,6 +70,7 @@ class StatusTransformer extends Fractal\TransformerAbstract
|
|||
'tags' => StatusHashtagService::statusTags($status->id),
|
||||
'poll' => $poll,
|
||||
'bookmarked' => BookmarkService::get($pid, $status->id),
|
||||
'edited_at' => $status->edited_at ? str_replace('+00:00', 'Z', $status->edited_at->format(DATE_RFC3339_EXTENDED)) : null,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ use App\Jobs\DeletePipeline\DeleteRemoteProfilePipeline;
|
|||
use App\Jobs\DeletePipeline\DeleteRemoteStatusPipeline;
|
||||
use App\Jobs\StoryPipeline\StoryExpire;
|
||||
use App\Jobs\StoryPipeline\StoryFetch;
|
||||
use App\Jobs\StatusPipeline\StatusRemoteUpdatePipeline;
|
||||
|
||||
use App\Util\ActivityPub\Validator\Accept as AcceptValidator;
|
||||
use App\Util\ActivityPub\Validator\Add as AddValidator;
|
||||
|
@ -128,9 +129,9 @@ class Inbox
|
|||
$this->handleFlagActivity();
|
||||
break;
|
||||
|
||||
// case 'Update':
|
||||
// (new UpdateActivity($this->payload, $this->profile))->handle();
|
||||
// break;
|
||||
case 'Update':
|
||||
$this->handleUpdateActivity();
|
||||
break;
|
||||
|
||||
default:
|
||||
// TODO: decide how to handle invalid verbs.
|
||||
|
@ -1207,4 +1208,19 @@ class Inbox
|
|||
|
||||
return;
|
||||
}
|
||||
|
||||
public function handleUpdateActivity()
|
||||
{
|
||||
$activity = $this->payload['object'];
|
||||
|
||||
if(!isset($activity['type'], $activity['id'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if($activity['type'] === 'Note') {
|
||||
if(Status::whereObjectUrl($activity['id'])->exists()) {
|
||||
StatusRemoteUpdatePipeline::dispatch($activity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@ return [
|
|||
// Cached public timeline for larger instances (beta)
|
||||
'cached_public_timeline' => env('EXP_CPT', false),
|
||||
|
||||
'cached_home_timeline' => env('EXP_CHT', false),
|
||||
|
||||
// Groups (unreleased)
|
||||
'gps' => env('EXP_GPS', false),
|
||||
|
||||
|
@ -33,4 +35,10 @@ return [
|
|||
|
||||
// Enforce Mastoapi Compatibility (alpha)
|
||||
'emc' => env('EXP_EMC', true),
|
||||
|
||||
// HLS Live Streaming
|
||||
'hls' => env('HLS_LIVE', false),
|
||||
|
||||
// Post Update/Edits
|
||||
'pue' => env('EXP_PUE', true),
|
||||
];
|
||||
|
|
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
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
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
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
|
@ -0,0 +1 @@
|
|||
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
|
File diff suppressed because one or more lines are too long
|
@ -1 +1 @@
|
|||
(()=>{"use strict";var e,r,t,n={},a={};function o(e){var r=a[e];if(void 0!==r)return r.exports;var t=a[e]={id:e,loaded:!1,exports:{}};return n[e].call(t.exports,t,t.exports,o),t.loaded=!0,t.exports}o.m=n,e=[],o.O=(r,t,n,a)=>{if(!t){var d=1/0;for(l=0;l<e.length;l++){for(var[t,n,a]=e[l],c=!0,i=0;i<t.length;i++)(!1&a||d>=a)&&Object.keys(o.O).every((e=>o.O[e](t[i])))?t.splice(i--,1):(c=!1,a<d&&(d=a));if(c){e.splice(l--,1);var s=n();void 0!==s&&(r=s)}}return r}a=a||0;for(var l=e.length;l>0&&e[l-1][2]>a;l--)e[l]=e[l-1];e[l]=[t,n,a]},o.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return o.d(r,{a:r}),r},o.d=(e,r)=>{for(var t in r)o.o(r,t)&&!o.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce(((r,t)=>(o.f[t](e,r),r)),[])),o.u=e=>"js/"+{1084:"profile~followers.bundle",1983:"kb.bundle",2470:"home.chunk",2521:"about.bundle",2530:"discover~myhashtags.chunk",2586:"compose.chunk",2732:"dms~message.chunk",3351:"discover~settings.chunk",3365:"dms.chunk",3623:"discover~findfriends.chunk",4028:"error404.bundle",4509:"static~privacy.bundle",4958:"discover.chunk",4965:"discover~memories.chunk",5865:"post.chunk",6053:"notifications.chunk",6869:"profile.chunk",7004:"help.bundle",7019:"discover~hashtag.bundle",8021:"contact.bundle",8250:"i18n.bundle",8517:"daci.chunk",8600:"changelog.bundle",8625:"profile~following.bundle",8900:"discover~serverfeed.chunk",9144:"static~tos.bundle"}[e]+"."+{1084:"fe353e697fb7660b",1983:"f6ebdaac1fd552ca",2470:"af8ef7b54f61b18d",2521:"44a18841089fdde3",2530:"089b7465b2359979",2586:"c413851da244ae3f",2732:"1cfdf19c4525eafa",3351:"5757ad3940569422",3365:"91ab72a8dcd1a8a8",3623:"1aabfedaab1849ba",4028:"5075813f1b00e10d",4509:"24c230550b6938b2",4958:"5ceb85dcb38dfbef",4965:"70b04c7698c2172b",5865:"62a9d21c9016fd95",6053:"9de71a122956c663",6869:"0f947cc09af5c8c3",7004:"7c1195b63e04d568",7019:"b8319d6999d3e2e3",8021:"d6c1d467c11796b1",8250:"9b9bf1b64e2aa1c1",8517:"3f13ec9fc49e9d2b",8600:"7f58a5ccc6659eb2",8625:"c406db7b14d07d36",8900:"ff59ca12d08bb810",9144:"65caad6c0546d8c9"}[e]+".js",o.miniCssF=e=>({138:"css/spa",703:"css/admin",1242:"css/appdark",6170:"css/app",8737:"css/portfolio",9994:"css/landing"}[e]+".css"),o.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),r={},t="pixelfed:",o.l=(e,n,a,d)=>{if(r[e])r[e].push(n);else{var c,i;if(void 0!==a)for(var s=document.getElementsByTagName("script"),l=0;l<s.length;l++){var u=s[l];if(u.getAttribute("src")==e||u.getAttribute("data-webpack")==t+a){c=u;break}}c||(i=!0,(c=document.createElement("script")).charset="utf-8",c.timeout=120,o.nc&&c.setAttribute("nonce",o.nc),c.setAttribute("data-webpack",t+a),c.src=e),r[e]=[n];var f=(t,n)=>{c.onerror=c.onload=null,clearTimeout(b);var a=r[e];if(delete r[e],c.parentNode&&c.parentNode.removeChild(c),a&&a.forEach((e=>e(n))),t)return t(n)},b=setTimeout(f.bind(null,void 0,{type:"timeout",target:c}),12e4);c.onerror=f.bind(null,c.onerror),c.onload=f.bind(null,c.onload),i&&document.head.appendChild(c)}},o.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),o.p="/",(()=>{var e={8929:0,1242:0,6170:0,8737:0,703:0,9994:0,138:0};o.f.j=(r,t)=>{var n=o.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else if(/^(1242|138|6170|703|8737|8929|9994)$/.test(r))e[r]=0;else{var a=new Promise(((t,a)=>n=e[r]=[t,a]));t.push(n[2]=a);var d=o.p+o.u(r),c=new Error;o.l(d,(t=>{if(o.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=t&&("load"===t.type?"missing":t.type),d=t&&t.target&&t.target.src;c.message="Loading chunk "+r+" failed.\n("+a+": "+d+")",c.name="ChunkLoadError",c.type=a,c.request=d,n[1](c)}}),"chunk-"+r,r)}},o.O.j=r=>0===e[r];var r=(r,t)=>{var n,a,[d,c,i]=t,s=0;if(d.some((r=>0!==e[r]))){for(n in c)o.o(c,n)&&(o.m[n]=c[n]);if(i)var l=i(o)}for(r&&r(t);s<d.length;s++)a=d[s],o.o(e,a)&&e[a]&&e[a][0](),e[a]=0;return o.O(l)},t=self.webpackChunkpixelfed=self.webpackChunkpixelfed||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})(),o.nc=void 0})();
|
||||
(()=>{"use strict";var e,r,a,t={},n={};function o(e){var r=n[e];if(void 0!==r)return r.exports;var a=n[e]={id:e,loaded:!1,exports:{}};return t[e].call(a.exports,a,a.exports,o),a.loaded=!0,a.exports}o.m=t,e=[],o.O=(r,a,t,n)=>{if(!a){var c=1/0;for(l=0;l<e.length;l++){for(var[a,t,n]=e[l],d=!0,i=0;i<a.length;i++)(!1&n||c>=n)&&Object.keys(o.O).every((e=>o.O[e](a[i])))?a.splice(i--,1):(d=!1,n<c&&(c=n));if(d){e.splice(l--,1);var s=t();void 0!==s&&(r=s)}}return r}n=n||0;for(var l=e.length;l>0&&e[l-1][2]>n;l--)e[l]=e[l-1];e[l]=[a,t,n]},o.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return o.d(r,{a:r}),r},o.d=(e,r)=>{for(var a in r)o.o(r,a)&&!o.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:r[a]})},o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce(((r,a)=>(o.f[a](e,r),r)),[])),o.u=e=>"js/"+{1084:"profile~followers.bundle",1983:"kb.bundle",2470:"home.chunk",2521:"about.bundle",2530:"discover~myhashtags.chunk",2586:"compose.chunk",2732:"dms~message.chunk",3351:"discover~settings.chunk",3365:"dms.chunk",3623:"discover~findfriends.chunk",4028:"error404.bundle",4509:"static~privacy.bundle",4958:"discover.chunk",4965:"discover~memories.chunk",5865:"post.chunk",6053:"notifications.chunk",6869:"profile.chunk",7004:"help.bundle",7019:"discover~hashtag.bundle",8021:"contact.bundle",8250:"i18n.bundle",8517:"daci.chunk",8600:"changelog.bundle",8625:"profile~following.bundle",8900:"discover~serverfeed.chunk",9144:"static~tos.bundle"}[e]+"."+{1084:"eac566ea09458e75",1983:"7c3d070a9bcc0489",2470:"f0ab2b4f7e84894c",2521:"dcf91eae809841f8",2530:"9aa66068d1e96512",2586:"eb564854474fa255",2732:"1d2a7a110371a12b",3351:"58f94c148a395667",3365:"a36285d6eee3b46f",3623:"1c4a19cf5fda27ad",4028:"f84c69eed21a7d82",4509:"60f5c03624e7626e",4958:"93193c6ec9a42fc4",4965:"a95b0149f5e4817f",5865:"fc948c7ae6cf23f0",6053:"fa21418a86f44a18",6869:"d1c4aa06ad944495",7004:"0d8a2725bcc8ed81",7019:"10cb33346c033ea7",8021:"97bd609a4737ae8d",8250:"83d55d158de68d01",8517:"e0ca30e5fa8c81f0",8600:"500c0754dd59045b",8625:"193b1268a32bbd07",8900:"48875685bb3cec75",9144:"d5389c3b8c2569d5"}[e]+".js",o.miniCssF=e=>({138:"css/spa",703:"css/admin",1242:"css/appdark",6170:"css/app",8737:"css/portfolio",9994:"css/landing"}[e]+".css"),o.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),r={},a="pixelfed:",o.l=(e,t,n,c)=>{if(r[e])r[e].push(t);else{var d,i;if(void 0!==n)for(var s=document.getElementsByTagName("script"),l=0;l<s.length;l++){var u=s[l];if(u.getAttribute("src")==e||u.getAttribute("data-webpack")==a+n){d=u;break}}d||(i=!0,(d=document.createElement("script")).charset="utf-8",d.timeout=120,o.nc&&d.setAttribute("nonce",o.nc),d.setAttribute("data-webpack",a+n),d.src=e),r[e]=[t];var f=(a,t)=>{d.onerror=d.onload=null,clearTimeout(b);var n=r[e];if(delete r[e],d.parentNode&&d.parentNode.removeChild(d),n&&n.forEach((e=>e(t))),a)return a(t)},b=setTimeout(f.bind(null,void 0,{type:"timeout",target:d}),12e4);d.onerror=f.bind(null,d.onerror),d.onload=f.bind(null,d.onload),i&&document.head.appendChild(d)}},o.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),o.p="/",(()=>{var e={8929:0,1242:0,6170:0,8737:0,703:0,9994:0,138:0};o.f.j=(r,a)=>{var t=o.o(e,r)?e[r]:void 0;if(0!==t)if(t)a.push(t[2]);else if(/^(1242|138|6170|703|8737|8929|9994)$/.test(r))e[r]=0;else{var n=new Promise(((a,n)=>t=e[r]=[a,n]));a.push(t[2]=n);var c=o.p+o.u(r),d=new Error;o.l(c,(a=>{if(o.o(e,r)&&(0!==(t=e[r])&&(e[r]=void 0),t)){var n=a&&("load"===a.type?"missing":a.type),c=a&&a.target&&a.target.src;d.message="Loading chunk "+r+" failed.\n("+n+": "+c+")",d.name="ChunkLoadError",d.type=n,d.request=c,t[1](d)}}),"chunk-"+r,r)}},o.O.j=r=>0===e[r];var r=(r,a)=>{var t,n,[c,d,i]=a,s=0;if(c.some((r=>0!==e[r]))){for(t in d)o.o(d,t)&&(o.m[t]=d[t]);if(i)var l=i(o)}for(r&&r(a);s<c.length;s++)n=c[s],o.o(e,n)&&e[n]&&e[n][0](),e[n]=0;return o.O(l)},a=self.webpackChunkpixelfed=self.webpackChunkpixelfed||[];a.forEach(r.bind(null,0)),a.push=r.bind(null,a.push.bind(a))})(),o.nc=void 0})();
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
|||
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
|
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
|
@ -64,17 +64,6 @@
|
|||
* Licensed under GPL 3.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Sizzle CSS Selector Engine v2.3.10
|
||||
* https://sizzlejs.com/
|
||||
*
|
||||
* Copyright JS Foundation and other contributors
|
||||
* Released under the MIT license
|
||||
* https://js.foundation/
|
||||
*
|
||||
* Date: 2023-02-14
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Vue.js v2.7.14
|
||||
* (c) 2014-2022 Evan You
|
||||
|
@ -82,17 +71,14 @@
|
|||
*/
|
||||
|
||||
/*!
|
||||
* jQuery JavaScript Library v3.6.4
|
||||
* jQuery JavaScript Library v3.7.0
|
||||
* https://jquery.com/
|
||||
*
|
||||
* Includes Sizzle.js
|
||||
* https://sizzlejs.com/
|
||||
*
|
||||
* Copyright OpenJS Foundation and other contributors
|
||||
* Released under the MIT license
|
||||
* https://jquery.org/license
|
||||
*
|
||||
* Date: 2023-03-08T15:28Z
|
||||
* Date: 2023-05-11T18:29Z
|
||||
*/
|
||||
|
||||
/*!
|
||||
|
@ -163,628 +149,8 @@ See the Apache Version 2.0 License for specific language governing permissions
|
|||
and limitations under the License.
|
||||
***************************************************************************** */
|
||||
|
||||
/*! ../controller/level-helper */
|
||||
|
||||
/*! ../crypt/decrypter */
|
||||
|
||||
/*! ../demux/aacdemuxer */
|
||||
|
||||
/*! ../demux/chunk-cache */
|
||||
|
||||
/*! ../demux/id3 */
|
||||
|
||||
/*! ../demux/mp3demuxer */
|
||||
|
||||
/*! ../demux/mp4demuxer */
|
||||
|
||||
/*! ../demux/transmuxer */
|
||||
|
||||
/*! ../demux/transmuxer-interface */
|
||||
|
||||
/*! ../demux/transmuxer-worker.ts */
|
||||
|
||||
/*! ../demux/tsdemuxer */
|
||||
|
||||
/*! ../errors */
|
||||
|
||||
/*! ../events */
|
||||
|
||||
/*! ../is-supported */
|
||||
|
||||
/*! ../loader/date-range */
|
||||
|
||||
/*! ../loader/fragment */
|
||||
|
||||
/*! ../loader/fragment-loader */
|
||||
|
||||
/*! ../loader/level-key */
|
||||
|
||||
/*! ../loader/load-stats */
|
||||
|
||||
/*! ../remux/mp4-remuxer */
|
||||
|
||||
/*! ../remux/passthrough-remuxer */
|
||||
|
||||
/*! ../task-loop */
|
||||
|
||||
/*! ../types/cmcd */
|
||||
|
||||
/*! ../types/demuxer */
|
||||
|
||||
/*! ../types/level */
|
||||
|
||||
/*! ../types/loader */
|
||||
|
||||
/*! ../types/transmuxer */
|
||||
|
||||
/*! ../utils/attr-list */
|
||||
|
||||
/*! ../utils/binary-search */
|
||||
|
||||
/*! ../utils/buffer-helper */
|
||||
|
||||
/*! ../utils/cea-608-parser */
|
||||
|
||||
/*! ../utils/codecs */
|
||||
|
||||
/*! ../utils/discontinuities */
|
||||
|
||||
/*! ../utils/ewma */
|
||||
|
||||
/*! ../utils/ewma-bandwidth-estimator */
|
||||
|
||||
/*! ../utils/hex */
|
||||
|
||||
/*! ../utils/imsc1-ttml-parser */
|
||||
|
||||
/*! ../utils/keysystem-util */
|
||||
|
||||
/*! ../utils/logger */
|
||||
|
||||
/*! ../utils/mediakeys-helper */
|
||||
|
||||
/*! ../utils/mediasource-helper */
|
||||
|
||||
/*! ../utils/mp4-tools */
|
||||
|
||||
/*! ../utils/numeric-encoding-utils */
|
||||
|
||||
/*! ../utils/output-filter */
|
||||
|
||||
/*! ../utils/texttrack-utils */
|
||||
|
||||
/*! ../utils/time-ranges */
|
||||
|
||||
/*! ../utils/timescale-conversion */
|
||||
|
||||
/*! ../utils/typed-array */
|
||||
|
||||
/*! ../utils/webvtt-parser */
|
||||
|
||||
/*! ./aac-helper */
|
||||
|
||||
/*! ./adts */
|
||||
|
||||
/*! ./aes-crypto */
|
||||
|
||||
/*! ./aes-decryptor */
|
||||
|
||||
/*! ./base-audio-demuxer */
|
||||
|
||||
/*! ./base-playlist-controller */
|
||||
|
||||
/*! ./base-stream-controller */
|
||||
|
||||
/*! ./buffer-operation-queue */
|
||||
|
||||
/*! ./config */
|
||||
|
||||
/*! ./controller/abr-controller */
|
||||
|
||||
/*! ./controller/audio-stream-controller */
|
||||
|
||||
/*! ./controller/audio-track-controller */
|
||||
|
||||
/*! ./controller/buffer-controller */
|
||||
|
||||
/*! ./controller/cap-level-controller */
|
||||
|
||||
/*! ./controller/cmcd-controller */
|
||||
|
||||
/*! ./controller/eme-controller */
|
||||
|
||||
/*! ./controller/fps-controller */
|
||||
|
||||
/*! ./controller/fragment-tracker */
|
||||
|
||||
/*! ./controller/id3-track-controller */
|
||||
|
||||
/*! ./controller/latency-controller */
|
||||
|
||||
/*! ./controller/level-controller */
|
||||
|
||||
/*! ./controller/stream-controller */
|
||||
|
||||
/*! ./controller/subtitle-stream-controller */
|
||||
|
||||
/*! ./controller/subtitle-track-controller */
|
||||
|
||||
/*! ./controller/timeline-controller */
|
||||
|
||||
/*! ./date-range */
|
||||
|
||||
/*! ./dummy-demuxed-track */
|
||||
|
||||
/*! ./errors */
|
||||
|
||||
/*! ./events */
|
||||
|
||||
/*! ./exp-golomb */
|
||||
|
||||
/*! ./fast-aes-key */
|
||||
|
||||
/*! ./fragment */
|
||||
|
||||
/*! ./fragment-finders */
|
||||
|
||||
/*! ./fragment-loader */
|
||||
|
||||
/*! ./fragment-tracker */
|
||||
|
||||
/*! ./gap-controller */
|
||||
|
||||
/*! ./hex */
|
||||
|
||||
/*! ./is-supported */
|
||||
|
||||
/*! ./level-details */
|
||||
|
||||
/*! ./level-helper */
|
||||
|
||||
/*! ./level-key */
|
||||
|
||||
/*! ./load-stats */
|
||||
|
||||
/*! ./loader/key-loader */
|
||||
|
||||
/*! ./loader/playlist-loader */
|
||||
|
||||
/*! ./logger */
|
||||
|
||||
/*! ./m3u8-parser */
|
||||
|
||||
/*! ./mp4-generator */
|
||||
|
||||
/*! ./mp4-remuxer */
|
||||
|
||||
/*! ./mp4-tools */
|
||||
|
||||
/*! ./mpegaudio */
|
||||
|
||||
/*! ./numeric-encoding-utils */
|
||||
|
||||
/*! ./sample-aes */
|
||||
|
||||
/*! ./src/polyfills/number */
|
||||
|
||||
/*! ./texttrack-utils */
|
||||
|
||||
/*! ./timescale-conversion */
|
||||
|
||||
/*! ./typed-array */
|
||||
|
||||
/*! ./types/level */
|
||||
|
||||
/*! ./utils/cues */
|
||||
|
||||
/*! ./utils/fetch-loader */
|
||||
|
||||
/*! ./utils/logger */
|
||||
|
||||
/*! ./utils/mediakeys-helper */
|
||||
|
||||
/*! ./utils/mediasource-helper */
|
||||
|
||||
/*! ./utils/xhr-loader */
|
||||
|
||||
/*! ./vttcue */
|
||||
|
||||
/*! ./vttparser */
|
||||
|
||||
/*! ./webvtt-parser */
|
||||
|
||||
/*! ./webworkify-webpack */
|
||||
|
||||
/*! eventemitter3 */
|
||||
|
||||
/*! https://mths.be/punycode v1.4.1 by @mathias */
|
||||
|
||||
/*! url-toolkit */
|
||||
|
||||
/*!********************!*\
|
||||
!*** ./src/hls.ts ***!
|
||||
\********************/
|
||||
|
||||
/*!***********************!*\
|
||||
!*** ./src/config.ts ***!
|
||||
\***********************/
|
||||
|
||||
/*!***********************!*\
|
||||
!*** ./src/errors.ts ***!
|
||||
\***********************/
|
||||
|
||||
/*!***********************!*\
|
||||
!*** ./src/events.ts ***!
|
||||
\***********************/
|
||||
|
||||
/*!**************************!*\
|
||||
!*** ./src/demux/id3.ts ***!
|
||||
\**************************/
|
||||
|
||||
/*!**************************!*\
|
||||
!*** ./src/task-loop.ts ***!
|
||||
\**************************/
|
||||
|
||||
/*!**************************!*\
|
||||
!*** ./src/utils/hex.ts ***!
|
||||
\**************************/
|
||||
|
||||
/*!***************************!*\
|
||||
!*** ./src/demux/adts.ts ***!
|
||||
\***************************/
|
||||
|
||||
/*!***************************!*\
|
||||
!*** ./src/types/cmcd.ts ***!
|
||||
\***************************/
|
||||
|
||||
/*!***************************!*\
|
||||
!*** ./src/utils/cues.ts ***!
|
||||
\***************************/
|
||||
|
||||
/*!***************************!*\
|
||||
!*** ./src/utils/ewma.ts ***!
|
||||
\***************************/
|
||||
|
||||
/*!****************************!*\
|
||||
!*** ./src/types/level.ts ***!
|
||||
\****************************/
|
||||
|
||||
/*!*****************************!*\
|
||||
!*** ./src/is-supported.ts ***!
|
||||
\*****************************/
|
||||
|
||||
/*!*****************************!*\
|
||||
!*** ./src/types/loader.ts ***!
|
||||
\*****************************/
|
||||
|
||||
/*!*****************************!*\
|
||||
!*** ./src/utils/codecs.ts ***!
|
||||
\*****************************/
|
||||
|
||||
/*!*****************************!*\
|
||||
!*** ./src/utils/logger.ts ***!
|
||||
\*****************************/
|
||||
|
||||
/*!*****************************!*\
|
||||
!*** ./src/utils/vttcue.ts ***!
|
||||
\*****************************/
|
||||
|
||||
/*!******************************!*\
|
||||
!*** ./src/types/demuxer.ts ***!
|
||||
\******************************/
|
||||
|
||||
/*!********************************!*\
|
||||
!*** ./src/crypt/decrypter.ts ***!
|
||||
\********************************/
|
||||
|
||||
/*!********************************!*\
|
||||
!*** ./src/demux/mpegaudio.ts ***!
|
||||
\********************************/
|
||||
|
||||
/*!********************************!*\
|
||||
!*** ./src/demux/tsdemuxer.ts ***!
|
||||
\********************************/
|
||||
|
||||
/*!********************************!*\
|
||||
!*** ./src/loader/fragment.ts ***!
|
||||
\********************************/
|
||||
|
||||
/*!********************************!*\
|
||||
!*** ./src/utils/attr-list.ts ***!
|
||||
\********************************/
|
||||
|
||||
/*!********************************!*\
|
||||
!*** ./src/utils/mp4-tools.ts ***!
|
||||
\********************************/
|
||||
|
||||
/*!********************************!*\
|
||||
!*** ./src/utils/vttparser.ts ***!
|
||||
\********************************/
|
||||
|
||||
/*!*********************************!*\
|
||||
!*** ./src/crypt/aes-crypto.ts ***!
|
||||
\*********************************/
|
||||
|
||||
/*!*********************************!*\
|
||||
!*** ./src/demux/aacdemuxer.ts ***!
|
||||
\*********************************/
|
||||
|
||||
/*!*********************************!*\
|
||||
!*** ./src/demux/exp-golomb.ts ***!
|
||||
\*********************************/
|
||||
|
||||
/*!*********************************!*\
|
||||
!*** ./src/demux/mp3demuxer.ts ***!
|
||||
\*********************************/
|
||||
|
||||
/*!*********************************!*\
|
||||
!*** ./src/demux/mp4demuxer.ts ***!
|
||||
\*********************************/
|
||||
|
||||
/*!*********************************!*\
|
||||
!*** ./src/demux/sample-aes.ts ***!
|
||||
\*********************************/
|
||||
|
||||
/*!*********************************!*\
|
||||
!*** ./src/demux/transmuxer.ts ***!
|
||||
\*********************************/
|
||||
|
||||
/*!*********************************!*\
|
||||
!*** ./src/loader/level-key.ts ***!
|
||||
\*********************************/
|
||||
|
||||
/*!*********************************!*\
|
||||
!*** ./src/polyfills/number.ts ***!
|
||||
\*********************************/
|
||||
|
||||
/*!*********************************!*\
|
||||
!*** ./src/remux/aac-helper.ts ***!
|
||||
\*********************************/
|
||||
|
||||
/*!*********************************!*\
|
||||
!*** ./src/types/transmuxer.ts ***!
|
||||
\*********************************/
|
||||
|
||||
/*!*********************************!*\
|
||||
!*** ./src/utils/xhr-loader.ts ***!
|
||||
\*********************************/
|
||||
|
||||
/*!**********************************!*\
|
||||
!*** ./src/demux/chunk-cache.ts ***!
|
||||
\**********************************/
|
||||
|
||||
/*!**********************************!*\
|
||||
!*** ./src/loader/date-range.ts ***!
|
||||
\**********************************/
|
||||
|
||||
/*!**********************************!*\
|
||||
!*** ./src/loader/key-loader.ts ***!
|
||||
\**********************************/
|
||||
|
||||
/*!**********************************!*\
|
||||
!*** ./src/loader/load-stats.ts ***!
|
||||
\**********************************/
|
||||
|
||||
/*!**********************************!*\
|
||||
!*** ./src/remux/mp4-remuxer.ts ***!
|
||||
\**********************************/
|
||||
|
||||
/*!**********************************!*\
|
||||
!*** ./src/utils/time-ranges.ts ***!
|
||||
\**********************************/
|
||||
|
||||
/*!**********************************!*\
|
||||
!*** ./src/utils/typed-array.ts ***!
|
||||
\**********************************/
|
||||
|
||||
/*!***********************************!*\
|
||||
!*** ./src/crypt/fast-aes-key.ts ***!
|
||||
\***********************************/
|
||||
|
||||
/*!***********************************!*\
|
||||
!*** ./src/loader/m3u8-parser.ts ***!
|
||||
\***********************************/
|
||||
|
||||
/*!***********************************!*\
|
||||
!*** ./src/utils/fetch-loader.ts ***!
|
||||
\***********************************/
|
||||
|
||||
/*!************************************!*\
|
||||
!*** ./src/crypt/aes-decryptor.ts ***!
|
||||
\************************************/
|
||||
|
||||
/*!************************************!*\
|
||||
!*** ./src/remux/mp4-generator.ts ***!
|
||||
\************************************/
|
||||
|
||||
/*!************************************!*\
|
||||
!*** ./src/utils/binary-search.ts ***!
|
||||
\************************************/
|
||||
|
||||
/*!************************************!*\
|
||||
!*** ./src/utils/buffer-helper.ts ***!
|
||||
\************************************/
|
||||
|
||||
/*!************************************!*\
|
||||
!*** ./src/utils/output-filter.ts ***!
|
||||
\************************************/
|
||||
|
||||
/*!************************************!*\
|
||||
!*** ./src/utils/webvtt-parser.ts ***!
|
||||
\************************************/
|
||||
|
||||
/*!*************************************!*\
|
||||
!*** ./src/loader/level-details.ts ***!
|
||||
\*************************************/
|
||||
|
||||
/*!*************************************!*\
|
||||
!*** ./src/utils/cea-608-parser.ts ***!
|
||||
\*************************************/
|
||||
|
||||
/*!*************************************!*\
|
||||
!*** ./src/utils/keysystem-util.ts ***!
|
||||
\*************************************/
|
||||
|
||||
/*!**************************************!*\
|
||||
!*** ./src/utils/discontinuities.ts ***!
|
||||
\**************************************/
|
||||
|
||||
/*!**************************************!*\
|
||||
!*** ./src/utils/texttrack-utils.ts ***!
|
||||
\**************************************/
|
||||
|
||||
/*!***************************************!*\
|
||||
!*** ./src/loader/fragment-loader.ts ***!
|
||||
\***************************************/
|
||||
|
||||
/*!***************************************!*\
|
||||
!*** ./src/loader/playlist-loader.ts ***!
|
||||
\***************************************/
|
||||
|
||||
/*!***************************************!*\
|
||||
!*** ./src/utils/mediakeys-helper.ts ***!
|
||||
\***************************************/
|
||||
|
||||
/*!****************************************!*\
|
||||
!*** ./src/controller/level-helper.ts ***!
|
||||
\****************************************/
|
||||
|
||||
/*!****************************************!*\
|
||||
!*** ./src/demux/transmuxer-worker.ts ***!
|
||||
\****************************************/
|
||||
|
||||
/*!****************************************!*\
|
||||
!*** ./src/utils/imsc1-ttml-parser.ts ***!
|
||||
\****************************************/
|
||||
|
||||
/*!*****************************************!*\
|
||||
!*** ./src/demux/base-audio-demuxer.ts ***!
|
||||
\*****************************************/
|
||||
|
||||
/*!*****************************************!*\
|
||||
!*** ./src/demux/webworkify-webpack.js ***!
|
||||
\*****************************************/
|
||||
|
||||
/*!*****************************************!*\
|
||||
!*** ./src/utils/mediasource-helper.ts ***!
|
||||
\*****************************************/
|
||||
|
||||
/*!******************************************!*\
|
||||
!*** ./src/controller/abr-controller.ts ***!
|
||||
\******************************************/
|
||||
|
||||
/*!******************************************!*\
|
||||
!*** ./src/controller/eme-controller.ts ***!
|
||||
\******************************************/
|
||||
|
||||
/*!******************************************!*\
|
||||
!*** ./src/controller/fps-controller.ts ***!
|
||||
\******************************************/
|
||||
|
||||
/*!******************************************!*\
|
||||
!*** ./src/controller/gap-controller.ts ***!
|
||||
\******************************************/
|
||||
|
||||
/*!******************************************!*\
|
||||
!*** ./src/demux/dummy-demuxed-track.ts ***!
|
||||
\******************************************/
|
||||
|
||||
/*!******************************************!*\
|
||||
!*** ./src/remux/passthrough-remuxer.ts ***!
|
||||
\******************************************/
|
||||
|
||||
/*!*******************************************!*\
|
||||
!*** ./src/controller/cmcd-controller.ts ***!
|
||||
\*******************************************/
|
||||
|
||||
/*!*******************************************!*\
|
||||
!*** ./src/demux/transmuxer-interface.ts ***!
|
||||
\*******************************************/
|
||||
|
||||
/*!*******************************************!*\
|
||||
!*** ./src/utils/timescale-conversion.ts ***!
|
||||
\*******************************************/
|
||||
|
||||
/*!********************************************!*\
|
||||
!*** ./src/controller/fragment-finders.ts ***!
|
||||
\********************************************/
|
||||
|
||||
/*!********************************************!*\
|
||||
!*** ./src/controller/fragment-tracker.ts ***!
|
||||
\********************************************/
|
||||
|
||||
/*!********************************************!*\
|
||||
!*** ./src/controller/level-controller.ts ***!
|
||||
\********************************************/
|
||||
|
||||
/*!*********************************************!*\
|
||||
!*** ./node_modules/eventemitter3/index.js ***!
|
||||
\*********************************************/
|
||||
|
||||
/*!*********************************************!*\
|
||||
!*** ./src/controller/buffer-controller.ts ***!
|
||||
\*********************************************/
|
||||
|
||||
/*!*********************************************!*\
|
||||
!*** ./src/controller/stream-controller.ts ***!
|
||||
\*********************************************/
|
||||
|
||||
/*!*********************************************!*\
|
||||
!*** ./src/utils/numeric-encoding-utils.ts ***!
|
||||
\*********************************************/
|
||||
|
||||
/*!**********************************************!*\
|
||||
!*** ./src/controller/latency-controller.ts ***!
|
||||
\**********************************************/
|
||||
|
||||
/*!***********************************************!*\
|
||||
!*** ./src/controller/timeline-controller.ts ***!
|
||||
\***********************************************/
|
||||
|
||||
/*!***********************************************!*\
|
||||
!*** ./src/utils/ewma-bandwidth-estimator.ts ***!
|
||||
\***********************************************/
|
||||
|
||||
/*!************************************************!*\
|
||||
!*** ./src/controller/cap-level-controller.ts ***!
|
||||
\************************************************/
|
||||
|
||||
/*!************************************************!*\
|
||||
!*** ./src/controller/id3-track-controller.ts ***!
|
||||
\************************************************/
|
||||
|
||||
/*!**************************************************!*\
|
||||
!*** ./src/controller/audio-track-controller.ts ***!
|
||||
\**************************************************/
|
||||
|
||||
/*!**************************************************!*\
|
||||
!*** ./src/controller/base-stream-controller.ts ***!
|
||||
\**************************************************/
|
||||
|
||||
/*!**************************************************!*\
|
||||
!*** ./src/controller/buffer-operation-queue.ts ***!
|
||||
\**************************************************/
|
||||
|
||||
/*!***************************************************!*\
|
||||
!*** ./src/controller/audio-stream-controller.ts ***!
|
||||
\***************************************************/
|
||||
|
||||
/*!****************************************************!*\
|
||||
!*** ./src/controller/base-playlist-controller.ts ***!
|
||||
\****************************************************/
|
||||
|
||||
/*!*****************************************************!*\
|
||||
!*** ./node_modules/url-toolkit/src/url-toolkit.js ***!
|
||||
\*****************************************************/
|
||||
|
||||
/*!*****************************************************!*\
|
||||
!*** ./src/controller/subtitle-track-controller.ts ***!
|
||||
\*****************************************************/
|
||||
|
||||
/*!******************************************************!*\
|
||||
!*** ./src/controller/subtitle-stream-controller.ts ***!
|
||||
\******************************************************/
|
||||
|
||||
/**
|
||||
* vue-class-component v7.2.3
|
||||
* (c) 2015-present Evan You
|
||||
|
|
|
@ -16,46 +16,46 @@
|
|||
"/js/profile-directory.js": "/js/profile-directory.js?id=24a2b981bffa2038f41284eed81eec71",
|
||||
"/js/story-compose.js": "/js/story-compose.js?id=cbb169145db25c0e92845710233771ac",
|
||||
"/js/direct.js": "/js/direct.js?id=5816111700ad8f8a89c932485f3a1e47",
|
||||
"/js/admin.js": "/js/admin.js?id=c9c9773a06e9fce9dd756381891a595b",
|
||||
"/js/live-player.js": "/js/live-player.js?id=c987b3cd69e432f1b3d52da2901ed305",
|
||||
"/js/admin.js": "/js/admin.js?id=529801d7a4eec7b0a30f97d1941a8dee",
|
||||
"/js/live-player.js": "/js/live-player.js?id=b07c9629c14e9952d1dbecca99ad21b6",
|
||||
"/js/spa.js": "/js/spa.js?id=7ecabb487fd27999e701d4f27132e3ac",
|
||||
"/js/stories.js": "/js/stories.js?id=4db94699502e85543192865879bece7d",
|
||||
"/js/portfolio.js": "/js/portfolio.js?id=646ebcbb4cab1dc0942dde3f8126940d",
|
||||
"/js/installer.js": "/js/installer.js?id=cd240ae970947b76ac49032ba95e0922",
|
||||
"/js/admin_invite.js": "/js/admin_invite.js?id=307a53250701e3b12164af9495e88447",
|
||||
"/js/landing.js": "/js/landing.js?id=7e3ab65813c4bf28182f5bdf0825774c",
|
||||
"/js/manifest.js": "/js/manifest.js?id=6a77f3ddb5e075cdea3d5b4a4ae50adb",
|
||||
"/js/home.chunk.af8ef7b54f61b18d.js": "/js/home.chunk.af8ef7b54f61b18d.js?id=798319a218acc5ccfcd5088a275a08a3",
|
||||
"/js/compose.chunk.c413851da244ae3f.js": "/js/compose.chunk.c413851da244ae3f.js?id=6389b021170bc21b58fc5bc28920f9af",
|
||||
"/js/post.chunk.62a9d21c9016fd95.js": "/js/post.chunk.62a9d21c9016fd95.js?id=df8928c784843ce754d2a1d6b7b70459",
|
||||
"/js/profile.chunk.0f947cc09af5c8c3.js": "/js/profile.chunk.0f947cc09af5c8c3.js?id=fbf3060fadbca5da7c77b174dca58782",
|
||||
"/js/discover~memories.chunk.70b04c7698c2172b.js": "/js/discover~memories.chunk.70b04c7698c2172b.js?id=437858b8ee0fce1fcaf4625b1ab669ba",
|
||||
"/js/discover~myhashtags.chunk.089b7465b2359979.js": "/js/discover~myhashtags.chunk.089b7465b2359979.js?id=daac449d68cd3030296937e709d6d5ab",
|
||||
"/js/daci.chunk.3f13ec9fc49e9d2b.js": "/js/daci.chunk.3f13ec9fc49e9d2b.js?id=e2cc591b5eec1bf8b825e6247595006b",
|
||||
"/js/discover~findfriends.chunk.1aabfedaab1849ba.js": "/js/discover~findfriends.chunk.1aabfedaab1849ba.js?id=1801453e5066687ec8f7a20832b77982",
|
||||
"/js/discover~serverfeed.chunk.ff59ca12d08bb810.js": "/js/discover~serverfeed.chunk.ff59ca12d08bb810.js?id=ceb384971dccbc3891fee0a33fdf977b",
|
||||
"/js/discover~settings.chunk.5757ad3940569422.js": "/js/discover~settings.chunk.5757ad3940569422.js?id=4d083efb280d6934177f7b007feded3a",
|
||||
"/js/discover.chunk.5ceb85dcb38dfbef.js": "/js/discover.chunk.5ceb85dcb38dfbef.js?id=01d27c04319b2be9e31b3c2ddf8f5d9e",
|
||||
"/js/notifications.chunk.9de71a122956c663.js": "/js/notifications.chunk.9de71a122956c663.js?id=f72a08113822f6ed5ab218a9ea21457d",
|
||||
"/js/dms.chunk.91ab72a8dcd1a8a8.js": "/js/dms.chunk.91ab72a8dcd1a8a8.js?id=752e3b061c1e76baa73b5d38657bf93e",
|
||||
"/js/dms~message.chunk.1cfdf19c4525eafa.js": "/js/dms~message.chunk.1cfdf19c4525eafa.js?id=bd3b4b71f23988bdfaf09ed817219cb9",
|
||||
"/js/profile~followers.bundle.fe353e697fb7660b.js": "/js/profile~followers.bundle.fe353e697fb7660b.js?id=dc50b57aa36b027c3f5a81efe9525bf2",
|
||||
"/js/profile~following.bundle.c406db7b14d07d36.js": "/js/profile~following.bundle.c406db7b14d07d36.js?id=b9088a98eeb05f06e241d398ffad5fbd",
|
||||
"/js/discover~hashtag.bundle.b8319d6999d3e2e3.js": "/js/discover~hashtag.bundle.b8319d6999d3e2e3.js?id=7371d3f4dbb5b598a300ad15b448c37b",
|
||||
"/js/error404.bundle.5075813f1b00e10d.js": "/js/error404.bundle.5075813f1b00e10d.js?id=a5c557f4d707537aa3f023a0786dfeba",
|
||||
"/js/help.bundle.7c1195b63e04d568.js": "/js/help.bundle.7c1195b63e04d568.js?id=5de97a307e5f3c6f1079fe57ff6f8294",
|
||||
"/js/kb.bundle.f6ebdaac1fd552ca.js": "/js/kb.bundle.f6ebdaac1fd552ca.js?id=d1d8c0f2c80a50471e4df88c0bd4ca0d",
|
||||
"/js/about.bundle.44a18841089fdde3.js": "/js/about.bundle.44a18841089fdde3.js?id=55b4ddaae96427389b23ab0dc12d44f0",
|
||||
"/js/contact.bundle.d6c1d467c11796b1.js": "/js/contact.bundle.d6c1d467c11796b1.js?id=453c2addc6c5a26681505de5a97b252d",
|
||||
"/js/i18n.bundle.9b9bf1b64e2aa1c1.js": "/js/i18n.bundle.9b9bf1b64e2aa1c1.js?id=06abe79741d5b8c93ad8de99edcd928d",
|
||||
"/js/static~privacy.bundle.24c230550b6938b2.js": "/js/static~privacy.bundle.24c230550b6938b2.js?id=3384a4144056cbda76c3d4aaab7d5120",
|
||||
"/js/static~tos.bundle.65caad6c0546d8c9.js": "/js/static~tos.bundle.65caad6c0546d8c9.js?id=6244cffbba6358ab51dbb877bda682ab",
|
||||
"/js/changelog.bundle.7f58a5ccc6659eb2.js": "/js/changelog.bundle.7f58a5ccc6659eb2.js?id=08c219b93662101da611a8196c6eb763",
|
||||
"/css/appdark.css": "/css/appdark.css?id=de85ecce91d9ed7afa7714547eb1e26c",
|
||||
"/css/app.css": "/css/app.css?id=88a0a931d5b0e24b0d9355f548414768",
|
||||
"/js/manifest.js": "/js/manifest.js?id=45a6e0c191e6273feb746da484394c3a",
|
||||
"/js/home.chunk.f0ab2b4f7e84894c.js": "/js/home.chunk.f0ab2b4f7e84894c.js?id=e50833f0517e9d9dd6aa6a669d40d437",
|
||||
"/js/compose.chunk.eb564854474fa255.js": "/js/compose.chunk.eb564854474fa255.js?id=6389b021170bc21b58fc5bc28920f9af",
|
||||
"/js/post.chunk.fc948c7ae6cf23f0.js": "/js/post.chunk.fc948c7ae6cf23f0.js?id=8406eeb0af7d6434fd61a98c900dac3a",
|
||||
"/js/profile.chunk.d1c4aa06ad944495.js": "/js/profile.chunk.d1c4aa06ad944495.js?id=e51bc6814dc77e32208b334ab9407990",
|
||||
"/js/discover~memories.chunk.a95b0149f5e4817f.js": "/js/discover~memories.chunk.a95b0149f5e4817f.js?id=e985938ef281130454b122067c5c14b6",
|
||||
"/js/discover~myhashtags.chunk.9aa66068d1e96512.js": "/js/discover~myhashtags.chunk.9aa66068d1e96512.js?id=282a85a9b97f9f92ad81c09107cd6ff9",
|
||||
"/js/daci.chunk.e0ca30e5fa8c81f0.js": "/js/daci.chunk.e0ca30e5fa8c81f0.js?id=f49da19e75645780accbef0645bf09ae",
|
||||
"/js/discover~findfriends.chunk.1c4a19cf5fda27ad.js": "/js/discover~findfriends.chunk.1c4a19cf5fda27ad.js?id=4be0346825149de564bba48b94595608",
|
||||
"/js/discover~serverfeed.chunk.48875685bb3cec75.js": "/js/discover~serverfeed.chunk.48875685bb3cec75.js?id=06748efc25e6d6dbc4eea20138b2de4d",
|
||||
"/js/discover~settings.chunk.58f94c148a395667.js": "/js/discover~settings.chunk.58f94c148a395667.js?id=01e9f3507bb4969ea24259c4c2f1caed",
|
||||
"/js/discover.chunk.93193c6ec9a42fc4.js": "/js/discover.chunk.93193c6ec9a42fc4.js?id=01d27c04319b2be9e31b3c2ddf8f5d9e",
|
||||
"/js/notifications.chunk.fa21418a86f44a18.js": "/js/notifications.chunk.fa21418a86f44a18.js?id=f72a08113822f6ed5ab218a9ea21457d",
|
||||
"/js/dms.chunk.a36285d6eee3b46f.js": "/js/dms.chunk.a36285d6eee3b46f.js?id=752e3b061c1e76baa73b5d38657bf93e",
|
||||
"/js/dms~message.chunk.1d2a7a110371a12b.js": "/js/dms~message.chunk.1d2a7a110371a12b.js?id=bd3b4b71f23988bdfaf09ed817219cb9",
|
||||
"/js/profile~followers.bundle.eac566ea09458e75.js": "/js/profile~followers.bundle.eac566ea09458e75.js?id=dc50b57aa36b027c3f5a81efe9525bf2",
|
||||
"/js/profile~following.bundle.193b1268a32bbd07.js": "/js/profile~following.bundle.193b1268a32bbd07.js?id=b9088a98eeb05f06e241d398ffad5fbd",
|
||||
"/js/discover~hashtag.bundle.10cb33346c033ea7.js": "/js/discover~hashtag.bundle.10cb33346c033ea7.js?id=7371d3f4dbb5b598a300ad15b448c37b",
|
||||
"/js/error404.bundle.f84c69eed21a7d82.js": "/js/error404.bundle.f84c69eed21a7d82.js?id=a5c557f4d707537aa3f023a0786dfeba",
|
||||
"/js/help.bundle.0d8a2725bcc8ed81.js": "/js/help.bundle.0d8a2725bcc8ed81.js?id=5de97a307e5f3c6f1079fe57ff6f8294",
|
||||
"/js/kb.bundle.7c3d070a9bcc0489.js": "/js/kb.bundle.7c3d070a9bcc0489.js?id=d1d8c0f2c80a50471e4df88c0bd4ca0d",
|
||||
"/js/about.bundle.dcf91eae809841f8.js": "/js/about.bundle.dcf91eae809841f8.js?id=55b4ddaae96427389b23ab0dc12d44f0",
|
||||
"/js/contact.bundle.97bd609a4737ae8d.js": "/js/contact.bundle.97bd609a4737ae8d.js?id=453c2addc6c5a26681505de5a97b252d",
|
||||
"/js/i18n.bundle.83d55d158de68d01.js": "/js/i18n.bundle.83d55d158de68d01.js?id=06abe79741d5b8c93ad8de99edcd928d",
|
||||
"/js/static~privacy.bundle.60f5c03624e7626e.js": "/js/static~privacy.bundle.60f5c03624e7626e.js?id=3384a4144056cbda76c3d4aaab7d5120",
|
||||
"/js/static~tos.bundle.d5389c3b8c2569d5.js": "/js/static~tos.bundle.d5389c3b8c2569d5.js?id=6244cffbba6358ab51dbb877bda682ab",
|
||||
"/js/changelog.bundle.500c0754dd59045b.js": "/js/changelog.bundle.500c0754dd59045b.js?id=08c219b93662101da611a8196c6eb763",
|
||||
"/css/appdark.css": "/css/appdark.css?id=7f9ba0a926020571e9c8fbedd2ec6a6f",
|
||||
"/css/app.css": "/css/app.css?id=838b7d90a81e16b8a9adc8644237606a",
|
||||
"/css/portfolio.css": "/css/portfolio.css?id=d98e354f173c6a8b729626384dceaa90",
|
||||
"/css/admin.css": "/css/admin.css?id=619b6c6613a24e232048856e72110862",
|
||||
"/css/landing.css": "/css/landing.css?id=b3df014b08177b3e7a4eae8fbe132708",
|
||||
"/css/spa.css": "/css/spa.css?id=6f1bfa8ad59f9d3e8f7a16827057a7a9",
|
||||
"/js/vendor.js": "/js/vendor.js?id=985cea6d09ed0f4c43ee3646a991ac84"
|
||||
"/css/admin.css": "/css/admin.css?id=0a66549bf79b75a0ca8cb83d11a4e2f4",
|
||||
"/css/landing.css": "/css/landing.css?id=589f3fa192867727925921b0f68ce022",
|
||||
"/css/spa.css": "/css/spa.css?id=f6bef1e343335ee2b5cf4e9fc074856f",
|
||||
"/js/vendor.js": "/js/vendor.js?id=84983046cff65e2066e3ab11c5a3db14"
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
</p>
|
||||
</div>
|
||||
<status
|
||||
:key="post.id"
|
||||
:key="post.id + ':fui:' + forceUpdateIdx"
|
||||
:status="post"
|
||||
:profile="user"
|
||||
v-on:menu="openContextMenu()"
|
||||
|
@ -83,6 +83,7 @@
|
|||
:profile="user"
|
||||
@report-modal="handleReport()"
|
||||
@delete="deletePost()"
|
||||
v-on:edit="handleEdit"
|
||||
/>
|
||||
|
||||
<likes-modal
|
||||
|
@ -105,6 +106,11 @@
|
|||
:status="post"
|
||||
/>
|
||||
|
||||
<post-edit-modal
|
||||
ref="editModal"
|
||||
v-on:update="mergeUpdatedPost"
|
||||
/>
|
||||
|
||||
<drawer />
|
||||
</div>
|
||||
</template>
|
||||
|
@ -119,6 +125,7 @@
|
|||
import LikesModal from './partials/post/LikeModal.vue';
|
||||
import SharesModal from './partials/post/ShareModal.vue';
|
||||
import ReportModal from './partials/modal/ReportPost.vue';
|
||||
import PostEditModal from './partials/post/PostEditModal.vue';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
|
@ -140,7 +147,8 @@
|
|||
"likes-modal": LikesModal,
|
||||
"shares-modal": SharesModal,
|
||||
"rightbar": Rightbar,
|
||||
"report-modal": ReportModal
|
||||
"report-modal": ReportModal,
|
||||
"post-edit-modal": PostEditModal
|
||||
},
|
||||
|
||||
data() {
|
||||
|
@ -156,7 +164,8 @@
|
|||
isReply: false,
|
||||
reply: {},
|
||||
showSharesModal: false,
|
||||
postStateError: false
|
||||
postStateError: false,
|
||||
forceUpdateIdx: 0
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -405,6 +414,17 @@
|
|||
break;
|
||||
}
|
||||
},
|
||||
|
||||
handleEdit(status) {
|
||||
this.$refs.editModal.show(status);
|
||||
},
|
||||
|
||||
mergeUpdatedPost(post) {
|
||||
this.post = post;
|
||||
this.$nextTick(() => {
|
||||
this.forceUpdateIdx++;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,233 @@
|
|||
<template>
|
||||
<div>
|
||||
<b-modal
|
||||
v-model="isOpen"
|
||||
centered
|
||||
size="md"
|
||||
:scrollable="true"
|
||||
hide-footer
|
||||
header-class="py-2"
|
||||
body-class="p-0"
|
||||
title-class="w-100 text-center pl-4 font-weight-bold"
|
||||
title-tag="p">
|
||||
<template #modal-header="{ close }">
|
||||
<template v-if="historyIndex === undefined">
|
||||
<div class="d-flex flex-grow-1 justify-content-between align-items-center">
|
||||
<span style="width:40px;"></span>
|
||||
<h5 class="font-weight-bold mb-0">Post History</h5>
|
||||
<b-button size="sm" variant="link" @click="close()">
|
||||
<i class="far fa-times text-dark fa-lg"></i>
|
||||
</b-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<div class="d-flex flex-grow-1 justify-content-between align-items-center pt-1">
|
||||
<b-button size="sm" variant="link" @click.prevent="historyIndex = undefined">
|
||||
<i class="fas fa-chevron-left text-primary fa-lg"></i>
|
||||
</b-button>
|
||||
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="d-flex align-items-center" style="gap: 5px;">
|
||||
<div class="d-flex align-items-center" style="gap: 5px;">
|
||||
<img
|
||||
:src="allHistory[0].account.avatar"
|
||||
width="16"
|
||||
height="16"
|
||||
class="rounded-circle"
|
||||
onerror="this.src='/storage/avatars/default.jpg';this.onerror=null;">
|
||||
<span class="font-weight-bold">{{ allHistory[0].account.username }}</span>
|
||||
</div>
|
||||
|
||||
<div>{{ historyIndex == (allHistory.length - 1) ? 'created' : 'edited' }} {{ formatTime(allHistory[historyIndex].created_at) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<b-button size="sm" variant="link" @click="close()">
|
||||
<i class="fas fa-times text-dark fa-lg"></i>
|
||||
</b-button>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<div v-if="isLoading" class="d-flex align-items-center justify-content-center" style="min-height: 500px;">
|
||||
<b-spinner />
|
||||
</div>
|
||||
|
||||
<template v-else>
|
||||
<div v-if="historyIndex === undefined" class="list-group border-top-0">
|
||||
<div
|
||||
v-for="(history, idx) in allHistory"
|
||||
class="list-group-item d-flex align-items-center justify-content-between" style="gap: 5px;">
|
||||
<div class="d-flex align-items-center" style="gap: 5px;">
|
||||
<div class="d-flex align-items-center" style="gap: 5px;">
|
||||
<img
|
||||
:src="history.account.avatar"
|
||||
width="24"
|
||||
height="24"
|
||||
class="rounded-circle"
|
||||
onerror="this.src='/storage/avatars/default.jpg';this.onerror=null;">
|
||||
<span class="font-weight-bold">{{ history.account.username }}</span>
|
||||
</div>
|
||||
<div>{{ idx == (allHistory.length - 1) ? 'created' : 'edited' }} {{ formatTime(history.created_at) }}</div>
|
||||
</div>
|
||||
|
||||
<a class="stretched-link text-decoration-none" href="#" @click.prevent="historyIndex = idx">
|
||||
<div class="d-flex align-items-center" style="gap:5px;">
|
||||
<i class="far fa-chevron-right text-primary fa-lg"></i>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="d-flex align-items-center flex-column border-top-0 justify-content-center">
|
||||
<!-- <img :src="allHistory[historyIndex].media_attachments[0].url" style="max-height: 400px;object-fit: contain;"> -->
|
||||
<template v-if="postType() === 'text'">
|
||||
</template>
|
||||
<template v-else-if="postType() === 'image'">
|
||||
<div style="width: 100%">
|
||||
<blur-hash-image
|
||||
:width="32"
|
||||
:height="32"
|
||||
:punch="1"
|
||||
class="img-contain border-bottom"
|
||||
:hash="allHistory[historyIndex].media_attachments[0].blurhash"
|
||||
:src="allHistory[historyIndex].media_attachments[0].url"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="postType() === 'album'">
|
||||
<div style="width: 100%">
|
||||
<b-carousel
|
||||
controls
|
||||
indicators
|
||||
background="#000000"
|
||||
style="text-shadow: 1px 1px 2px #333;"
|
||||
>
|
||||
<b-carousel-slide
|
||||
v-for="(media, idx) in allHistory[historyIndex].media_attachments"
|
||||
:key="'pfph:'+media.id+':'+idx"
|
||||
:img-src="media.url"
|
||||
></b-carousel-slide>
|
||||
</b-carousel>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="postType() === 'video'">
|
||||
<div style="width: 100%">
|
||||
<div class="embed-responsive embed-responsive-16by9 border-bottom">
|
||||
<video class="video" controls playsinline preload="metadata" loop>
|
||||
<source :src="allHistory[historyIndex].media_attachments[0].url" :type="allHistory[historyIndex].media_attachments[0].mime">
|
||||
</video>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<p class="lead my-4" v-html="allHistory[historyIndex].content"></p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</b-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script type="text/javascript">
|
||||
export default {
|
||||
props: {
|
||||
status: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
isOpen: false,
|
||||
isLoading: true,
|
||||
allHistory: [],
|
||||
historyIndex: undefined,
|
||||
user: window._sharedData.user
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
open() {
|
||||
this.isOpen = true;
|
||||
this.isLoading = true;
|
||||
this.historyIndex = undefined;
|
||||
this.allHistory = [];
|
||||
setTimeout(() => {
|
||||
this.fetchHistory();
|
||||
}, 300);
|
||||
},
|
||||
|
||||
fetchHistory() {
|
||||
axios.get(`/api/v1/statuses/${this.status.id}/history`)
|
||||
.then(res => {
|
||||
this.allHistory = res.data;
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false;
|
||||
})
|
||||
},
|
||||
|
||||
formatTime(ts) {
|
||||
let date = Date.parse(ts);
|
||||
let seconds = Math.floor((new Date() - date) / 1000);
|
||||
let interval = Math.floor(seconds / 63072000);
|
||||
if (interval < 0) {
|
||||
return "0s";
|
||||
}
|
||||
if (interval >= 1) {
|
||||
return interval + (interval == 1 ? ' year' : ' years') + " ago";
|
||||
}
|
||||
interval = Math.floor(seconds / 604800);
|
||||
if (interval >= 1) {
|
||||
return interval + (interval == 1 ? ' week' : ' weeks') + " ago";
|
||||
}
|
||||
interval = Math.floor(seconds / 86400);
|
||||
if (interval >= 1) {
|
||||
return interval + (interval == 1 ? ' day' : ' days') + " ago";
|
||||
}
|
||||
interval = Math.floor(seconds / 3600);
|
||||
if (interval >= 1) {
|
||||
return interval + (interval == 1 ? ' hour' : ' hours') + " ago";
|
||||
}
|
||||
interval = Math.floor(seconds / 60);
|
||||
if (interval >= 1) {
|
||||
return interval + (interval == 1 ? ' minute' : ' minutes') + " ago";
|
||||
}
|
||||
return Math.floor(seconds) + " seconds ago";
|
||||
},
|
||||
|
||||
postType() {
|
||||
if(this.historyIndex === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
let post = this.allHistory[this.historyIndex];
|
||||
|
||||
if(!post) {
|
||||
return 'text';
|
||||
}
|
||||
|
||||
let media = post.media_attachments;
|
||||
|
||||
if(!media || !media.length) {
|
||||
return 'text';
|
||||
}
|
||||
|
||||
if(media.length == 1) {
|
||||
return media[0].type;
|
||||
}
|
||||
|
||||
return 'album';
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.img-contain {
|
||||
img {
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,348 @@
|
|||
<template>
|
||||
<div class="card-header border-0" style="border-top-left-radius: 15px;border-top-right-radius: 15px;">
|
||||
<div class="media align-items-center">
|
||||
<a :href="status.account.url" @click.prevent="goToProfile()" style="margin-right: 10px;">
|
||||
<img :src="getStatusAvatar()" style="border-radius:15px;" width="44" height="44" onerror="this.onerror=null;this.src='/storage/avatars/default.png?v=0';">
|
||||
</a>
|
||||
|
||||
<div class="media-body">
|
||||
<p class="font-weight-bold username">
|
||||
<a :href="status.account.url" class="text-dark" :id="'apop_'+status.id" @click.prevent="goToProfile">
|
||||
{{ status.account.acct }}
|
||||
</a>
|
||||
<b-popover :target="'apop_'+status.id" triggers="hover" placement="bottom" custom-class="shadow border-0 rounded-px">
|
||||
<profile-hover-card
|
||||
:profile="status.account"
|
||||
v-on:follow="follow"
|
||||
v-on:unfollow="unfollow" />
|
||||
</b-popover>
|
||||
</p>
|
||||
<p class="text-lighter mb-0" style="font-size: 13px;">
|
||||
<span v-if="status.account.is_admin" class="d-none d-md-inline-block">
|
||||
<span class="badge badge-light text-danger user-select-none" title="Admin account">ADMIN</span>
|
||||
<span class="mx-1 text-lighter">·</span>
|
||||
</span>
|
||||
<a class="timestamp text-lighter" :href="status.url" @click.prevent="goToPost()" :title="status.created_at">
|
||||
{{ timeago(status.created_at) }}
|
||||
</a>
|
||||
|
||||
<span v-if="config.ab.pue && status.hasOwnProperty('edited_at') && status.edited_at">
|
||||
<span class="mx-1 text-lighter">·</span>
|
||||
<a class="text-lighter" href="#" @click.prevent="openEditModal">Edited</a>
|
||||
</span>
|
||||
|
||||
<span class="mx-1 text-lighter">·</span>
|
||||
<span class="visibility text-lighter" :title="scopeTitle(status.visibility)"><i :class="scopeIcon(status.visibility)"></i></span>
|
||||
|
||||
<span v-if="status.place && status.place.hasOwnProperty('name')" class="d-none d-md-inline-block">
|
||||
<span class="mx-1 text-lighter">·</span>
|
||||
<span class="location text-lighter"><i class="far fa-map-marker-alt"></i> {{ status.place.name }}, {{ status.place.country }}</span>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<button v-if="!useDropdownMenu" class="btn btn-link text-lighter" @click="openMenu">
|
||||
<i class="far fa-ellipsis-v fa-lg"></i>
|
||||
</button>
|
||||
|
||||
<b-dropdown
|
||||
v-else
|
||||
no-caret
|
||||
right
|
||||
variant="link"
|
||||
toggle-class="text-lighter"
|
||||
html="<i class='far fa-ellipsis-v fa-lg px-3'></i>"
|
||||
>
|
||||
<b-dropdown-item>
|
||||
<p class="mb-0 font-weight-bold">{{ $t('menu.viewPost') }}</p>
|
||||
</b-dropdown-item>
|
||||
<b-dropdown-item>
|
||||
<p class="mb-0 font-weight-bold">{{ $t('common.copyLink') }}</p>
|
||||
</b-dropdown-item>
|
||||
<b-dropdown-item v-if="status.local">
|
||||
<p class="mb-0 font-weight-bold">{{ $t('menu.embed') }}</p>
|
||||
</b-dropdown-item>
|
||||
<b-dropdown-divider v-if="!owner"></b-dropdown-divider>
|
||||
<b-dropdown-item v-if="!owner">
|
||||
<p class="mb-0 font-weight-bold">{{ $t('menu.report') }}</p>
|
||||
<p class="small text-muted mb-0">Report content that violate our rules</p>
|
||||
</b-dropdown-item>
|
||||
<b-dropdown-item v-if="!owner && status.hasOwnProperty('relationship')">
|
||||
<p class="mb-0 font-weight-bold">{{ status.relationship.muting ? 'Unmute' : 'Mute' }}</p>
|
||||
<p class="small text-muted mb-0">Hide posts from this account in your feeds</p>
|
||||
</b-dropdown-item>
|
||||
<b-dropdown-item v-if="!owner && status.hasOwnProperty('relationship')">
|
||||
<p class="mb-0 font-weight-bold text-danger">{{ status.relationship.blocking ? 'Unblock' : 'Block' }}</p>
|
||||
<p class="small text-muted mb-0">Restrict all content from this account</p>
|
||||
</b-dropdown-item>
|
||||
<b-dropdown-divider v-if="owner || admin"></b-dropdown-divider>
|
||||
<b-dropdown-item v-if="owner || admin">
|
||||
<p class="mb-0 font-weight-bold text-danger">
|
||||
{{ $t('common.delete') }}
|
||||
</p>
|
||||
</b-dropdown-item>
|
||||
</b-dropdown>
|
||||
</div>
|
||||
|
||||
<edit-history-modal ref="editModal" :status="status" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script type="text/javascript">
|
||||
import ProfileHoverCard from './../profile/ProfileHoverCard.vue';
|
||||
import EditHistoryModal from './EditHistoryModal.vue';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
status: {
|
||||
type: Object
|
||||
},
|
||||
|
||||
profile: {
|
||||
type: Object
|
||||
},
|
||||
|
||||
useDropdownMenu: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
|
||||
components: {
|
||||
"profile-hover-card": ProfileHoverCard,
|
||||
"edit-history-modal": EditHistoryModal
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
config: window.App.config,
|
||||
menuLoading: true,
|
||||
owner: false,
|
||||
admin: false,
|
||||
license: false
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
timeago(ts) {
|
||||
let short = App.util.format.timeAgo(ts);
|
||||
if(
|
||||
short.endsWith('s') ||
|
||||
short.endsWith('m') ||
|
||||
short.endsWith('h')
|
||||
) {
|
||||
return short;
|
||||
}
|
||||
const intl = new Intl.DateTimeFormat(undefined, {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric'
|
||||
});
|
||||
return intl.format(new Date(ts));
|
||||
},
|
||||
|
||||
openMenu() {
|
||||
this.$emit('menu');
|
||||
},
|
||||
|
||||
scopeIcon(scope) {
|
||||
switch(scope) {
|
||||
case 'public':
|
||||
return 'far fa-globe';
|
||||
break;
|
||||
|
||||
case 'unlisted':
|
||||
return 'far fa-lock-open';
|
||||
break;
|
||||
|
||||
case 'private':
|
||||
return 'far fa-lock';
|
||||
break;
|
||||
|
||||
default:
|
||||
return 'far fa-globe';
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
scopeTitle(scope) {
|
||||
switch(scope) {
|
||||
case 'public':
|
||||
return 'Visible to everyone';
|
||||
break;
|
||||
|
||||
case 'unlisted':
|
||||
return 'Hidden from public feeds';
|
||||
break;
|
||||
|
||||
case 'private':
|
||||
return 'Only visible to followers';
|
||||
break;
|
||||
|
||||
default:
|
||||
return '';
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
goToPost() {
|
||||
if(location.pathname.split('/').pop() == this.status.id) {
|
||||
location.href = this.status.local ? this.status.url + '?fs=1' : this.status.url;
|
||||
return;
|
||||
}
|
||||
|
||||
this.$router.push({
|
||||
name: 'post',
|
||||
path: `/i/web/post/${this.status.id}`,
|
||||
params: {
|
||||
id: this.status.id,
|
||||
cachedStatus: this.status,
|
||||
cachedProfile: this.profile
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
goToProfile() {
|
||||
this.$nextTick(() => {
|
||||
this.$router.push({
|
||||
name: 'profile',
|
||||
path: `/i/web/profile/${this.status.account.id}`,
|
||||
params: {
|
||||
id: this.status.account.id,
|
||||
cachedProfile: this.status.account,
|
||||
cachedUser: this.profile
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
toggleContentWarning() {
|
||||
this.key++;
|
||||
this.sensitive = true;
|
||||
this.status.sensitive = !this.status.sensitive;
|
||||
},
|
||||
|
||||
like() {
|
||||
event.currentTarget.blur();
|
||||
if(this.status.favourited) {
|
||||
this.$emit('unlike');
|
||||
} else {
|
||||
this.$emit('like');
|
||||
}
|
||||
},
|
||||
|
||||
toggleMenu(bvEvent) {
|
||||
setTimeout(() => {
|
||||
this.menuLoading = false;
|
||||
}, 500);
|
||||
},
|
||||
|
||||
closeMenu(bvEvent) {
|
||||
setTimeout(() => {
|
||||
bvEvent.target.parentNode.firstElementChild.blur();
|
||||
}, 100);
|
||||
},
|
||||
|
||||
showLikes() {
|
||||
event.currentTarget.blur();
|
||||
this.$emit('likes-modal');
|
||||
},
|
||||
|
||||
showShares() {
|
||||
event.currentTarget.blur();
|
||||
this.$emit('shares-modal');
|
||||
},
|
||||
|
||||
showComments() {
|
||||
event.currentTarget.blur();
|
||||
this.showCommentDrawer = !this.showCommentDrawer;
|
||||
},
|
||||
|
||||
copyLink() {
|
||||
event.currentTarget.blur();
|
||||
App.util.clipboard(this.status.url);
|
||||
},
|
||||
|
||||
shareToOther() {
|
||||
if (navigator.canShare) {
|
||||
navigator.share({
|
||||
url: this.status.url
|
||||
})
|
||||
.then(() => console.log('Share was successful.'))
|
||||
.catch((error) => console.log('Sharing failed', error));
|
||||
} else {
|
||||
swal('Not supported', 'Your current device does not support native sharing.', 'error');
|
||||
}
|
||||
},
|
||||
|
||||
counterChange(type) {
|
||||
this.$emit('counter-change', type);
|
||||
},
|
||||
|
||||
showCommentLikes(post) {
|
||||
this.$emit('comment-likes-modal', post);
|
||||
},
|
||||
|
||||
shareStatus() {
|
||||
this.$emit('share');
|
||||
},
|
||||
|
||||
unshareStatus() {
|
||||
this.$emit('unshare');
|
||||
},
|
||||
|
||||
handleReport(post) {
|
||||
this.$emit('handle-report', post);
|
||||
},
|
||||
|
||||
follow() {
|
||||
this.$emit('follow');
|
||||
},
|
||||
|
||||
unfollow() {
|
||||
this.$emit('unfollow');
|
||||
},
|
||||
|
||||
handleReblog() {
|
||||
this.isReblogging = true;
|
||||
if(this.status.reblogged) {
|
||||
this.$emit('unshare');
|
||||
} else {
|
||||
this.$emit('share');
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
this.isReblogging = false;
|
||||
}, 5000);
|
||||
},
|
||||
|
||||
handleBookmark() {
|
||||
event.currentTarget.blur();
|
||||
this.isBookmarking = true;
|
||||
this.$emit('bookmark');
|
||||
|
||||
setTimeout(() => {
|
||||
this.isBookmarking = false;
|
||||
}, 5000);
|
||||
},
|
||||
|
||||
getStatusAvatar() {
|
||||
if(window._sharedData.user.id == this.status.account.id) {
|
||||
return window._sharedData.user.avatar;
|
||||
}
|
||||
|
||||
return this.status.account.avatar;
|
||||
},
|
||||
|
||||
openModTools() {
|
||||
this.$emit('mod-tools');
|
||||
},
|
||||
|
||||
openEditModal() {
|
||||
this.$refs.editModal.open();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -13,3 +13,23 @@ body, button, input, textarea {
|
|||
font-size: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-pills .nav-item {
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
.list-fade-bottom {
|
||||
position: relative;
|
||||
|
||||
&:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
background-image: linear-gradient(to bottom, rgba(255,255,255, 0), rgba(255,255,255, 1) 90%);
|
||||
width: 100%;
|
||||
height: 10em;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -210,6 +210,7 @@ a.text-dark:hover {
|
|||
|
||||
.autocomplete-result-list {
|
||||
background: var(--light) !important;
|
||||
z-index: 2 !important;
|
||||
}
|
||||
|
||||
.dropdown-menu,
|
||||
|
@ -261,7 +262,8 @@ span.twitter-typeahead .tt-suggestion:focus {
|
|||
border-color: var(--border-color) !important;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
.modal-header,
|
||||
.modal-footer {
|
||||
border-color: var(--border-color);
|
||||
}
|
||||
|
||||
|
@ -328,3 +330,66 @@ span.twitter-typeahead .tt-suggestion:focus {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.compose-modal-component {
|
||||
.form-control:focus {
|
||||
color: var(--body-color);
|
||||
}
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
.nav-tabs .nav-link.active,
|
||||
.nav-tabs .nav-item.show .nav-link {
|
||||
background-color: transparent;
|
||||
border-color: var(--border-color);
|
||||
}
|
||||
|
||||
.nav-tabs .nav-link:hover,
|
||||
.nav-tabs .nav-link:focus {
|
||||
border-color: var(--border-color);
|
||||
}
|
||||
|
||||
.form-control:focus {
|
||||
color: var(--body-color);
|
||||
}
|
||||
}
|
||||
|
||||
.tribute-container {
|
||||
border: 0;
|
||||
|
||||
ul {
|
||||
margin-top: 0;
|
||||
border-color: var(--border-color);
|
||||
}
|
||||
|
||||
li {
|
||||
padding: 0.5rem 1rem;
|
||||
border-top: 0;
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
font-size: 13px;
|
||||
|
||||
&:not(:last-child) {
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
&.highlight,
|
||||
&:hover {
|
||||
color: var(--body-color);
|
||||
font-weight: bold;
|
||||
background: rgba(44, 120, 191, 0.25);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.timeline-status-component {
|
||||
.username {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||
margin-bottom: -3px;
|
||||
word-break: break-word;
|
||||
|
||||
@media (min-width: 768px) {
|
||||
font-size: 17px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,6 +94,9 @@ Route::group(['prefix' => 'api'], function() use($middleware) {
|
|||
Route::post('tags/{id}/follow', 'Api\ApiV1Controller@followHashtag')->middleware($middleware);
|
||||
Route::post('tags/{id}/unfollow', 'Api\ApiV1Controller@unfollowHashtag')->middleware($middleware);
|
||||
Route::get('tags/{id}', 'Api\ApiV1Controller@getHashtag')->middleware($middleware);
|
||||
|
||||
Route::get('statuses/{id}/history', 'StatusEditController@history')->middleware($middleware);
|
||||
Route::put('statuses/{id}', 'StatusEditController@store')->middleware($middleware);
|
||||
});
|
||||
|
||||
Route::group(['prefix' => 'v2'], function() use($middleware) {
|
||||
|
|
Loading…
Reference in New Issue