Merge branch 'staging' of github.com:mbliznikova/pixelfed into staging

pull/4750/head
mbliznikova 2023-10-23 18:46:11 +00:00
commit e3de4c3e68
84 zmienionych plików z 3049 dodań i 978 usunięć

Wyświetl plik

@ -4,6 +4,7 @@
### Added
- Resilient Media Storage ([#4665](https://github.com/pixelfed/pixelfed/pull/4665)) ([fb1deb6](https://github.com/pixelfed/pixelfed/commit/fb1deb6))
- Video WebP2P ([#4713](https://github.com/pixelfed/pixelfed/pull/4713)) ([0405ef12](https://github.com/pixelfed/pixelfed/commit/0405ef12))
- Added user:2fa command to easily disable 2FA for given account ([c6408fd7](https://github.com/pixelfed/pixelfed/commit/c6408fd7))
- Added `avatar:storage-deep-clean` command to dispatch remote avatar storage cleanup jobs ([c37b7cde](https://github.com/pixelfed/pixelfed/commit/c37b7cde))
@ -34,6 +35,8 @@
- Update CreateAvatar job, add processing constraints and set `is_remote` attribute ([319ced40](https://github.com/pixelfed/pixelfed/commit/319ced40))
- Update RemoteStatusDelete and DecrementPostCount pipelines ([edbcf3ed](https://github.com/pixelfed/pixelfed/commit/edbcf3ed))
- Update lexer regex, fix mention regex and add more tests ([778e83d3](https://github.com/pixelfed/pixelfed/commit/778e83d3))
- Update StatusTransformer, generate autolink on request ([dfe2379b](https://github.com/pixelfed/pixelfed/commit/dfe2379b))
- Update ComposeModal component, fix multi filter bug and allow media re-ordering before upload/posting ([56e315f6](https://github.com/pixelfed/pixelfed/commit/56e315f6))
- ([](https://github.com/pixelfed/pixelfed/commit/))
## [v0.11.9 (2023-08-21)](https://github.com/pixelfed/pixelfed/compare/v0.11.8...v0.11.9)

Wyświetl plik

@ -10,8 +10,11 @@ use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Storage;
use App\Services\Media\MediaHlsService;
use Illuminate\Queue\Middleware\WithoutOverlapping;
use Illuminate\Contracts\Queue\ShouldBeUniqueUntilProcessing;
class MediaDeletePipeline implements ShouldQueue
class MediaDeletePipeline implements ShouldQueue, ShouldBeUniqueUntilProcessing
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
@ -20,8 +23,34 @@ class MediaDeletePipeline implements ShouldQueue
public $timeout = 300;
public $tries = 3;
public $maxExceptions = 1;
public $failOnTimeout = true;
public $deleteWhenMissingModels = true;
/**
* The number of seconds after which the job's unique lock will be released.
*
* @var int
*/
public $uniqueFor = 3600;
/**
* Get the unique ID for the job.
*/
public function uniqueId(): string
{
return 'media:purge-job:id-' . $this->media->id;
}
/**
* Get the middleware the job should pass through.
*
* @return array<int, object>
*/
public function middleware(): array
{
return [(new WithoutOverlapping("media:purge-job:id-{$this->media->id}"))->shared()->dontRelease()];
}
public function __construct(Media $media)
{
$this->media = $media;
@ -63,9 +92,17 @@ class MediaDeletePipeline implements ShouldQueue
$disk->delete($thumb);
}
if($media->hls_path != null) {
$files = MediaHlsService::allFiles($media);
if($files && count($files)) {
foreach($files as $file) {
$disk->delete($file);
}
}
}
$media->delete();
return 1;
}
}

Wyświetl plik

@ -0,0 +1,109 @@
<?php
namespace App\Jobs\VideoPipeline;
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 FFMpeg\Format\Video\X264;
use FFMpeg;
use Cache;
use App\Services\MediaService;
use App\Services\StatusService;
use Illuminate\Queue\Middleware\WithoutOverlapping;
use Illuminate\Contracts\Queue\ShouldBeUniqueUntilProcessing;
class VideoHlsPipeline implements ShouldQueue, ShouldBeUniqueUntilProcessing
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $media;
public $timeout = 900;
public $tries = 3;
public $maxExceptions = 1;
public $failOnTimeout = true;
public $deleteWhenMissingModels = true;
/**
* The number of seconds after which the job's unique lock will be released.
*
* @var int
*/
public $uniqueFor = 3600;
/**
* Get the unique ID for the job.
*/
public function uniqueId(): string
{
return 'media:video-hls:id-' . $this->media->id;
}
/**
* Get the middleware the job should pass through.
*
* @return array<int, object>
*/
public function middleware(): array
{
return [(new WithoutOverlapping("media:video-hls:id-{$this->media->id}"))->shared()->dontRelease()];
}
/**
* Create a new job instance.
*/
public function __construct($media)
{
$this->media = $media;
}
/**
* Execute the job.
*/
public function handle(): void
{
$depCheck = Cache::rememberForever('video-pipeline:hls:depcheck', function() {
$bin = config('laravel-ffmpeg.ffmpeg.binaries');
$output = shell_exec($bin . ' -version');
if($output && preg_match('/ffmpeg version ([^\s]+)/', $output, $matches)) {
$version = $matches[1];
return (version_compare($version, config('laravel-ffmpeg.min_hls_version')) >= 0) ? 'ok' : false;
} else {
return false;
}
});
if(!$depCheck || $depCheck !== 'ok') {
return;
}
$media = $this->media;
$bitrate = (new X264)->setKiloBitrate(config('media.hls.bitrate') ?? 1000);
$mp4 = $media->media_path;
$man = str_replace('.mp4', '.m3u8', $mp4);
FFMpeg::fromDisk('local')
->open($mp4)
->exportForHLS()
->setSegmentLength(16)
->setKeyFrameInterval(48)
->addFormat($bitrate)
->save($man);
$media->hls_path = $man;
$media->hls_transcoded_at = now();
$media->save();
MediaService::del($media->status_id);
usleep(50000);
StatusService::del($media->status_id);
return;
}
}

Wyświetl plik

@ -16,13 +16,46 @@ use App\Jobs\MediaPipeline\MediaStoragePipeline;
use App\Util\Media\Blurhash;
use App\Services\MediaService;
use App\Services\StatusService;
use Illuminate\Queue\Middleware\WithoutOverlapping;
use Illuminate\Contracts\Queue\ShouldBeUniqueUntilProcessing;
class VideoThumbnail implements ShouldQueue
class VideoThumbnail implements ShouldQueue, ShouldBeUniqueUntilProcessing
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $media;
public $timeout = 900;
public $tries = 3;
public $maxExceptions = 1;
public $failOnTimeout = true;
public $deleteWhenMissingModels = true;
/**
* The number of seconds after which the job's unique lock will be released.
*
* @var int
*/
public $uniqueFor = 3600;
/**
* Get the unique ID for the job.
*/
public function uniqueId(): string
{
return 'media:video-thumb:id-' . $this->media->id;
}
/**
* Get the middleware the job should pass through.
*
* @return array<int, object>
*/
public function middleware(): array
{
return [(new WithoutOverlapping("media:video-thumb:id-{$this->media->id}"))->shared()->dontRelease()];
}
/**
* Create a new job instance.
*
@ -54,7 +87,7 @@ class VideoThumbnail implements ShouldQueue
$path[$i] = $t;
$save = implode('/', $path);
$video = FFMpeg::open($base)
->getFrameFromSeconds(0)
->getFrameFromSeconds(1)
->export()
->toDisk('local')
->save($save);
@ -68,6 +101,9 @@ class VideoThumbnail implements ShouldQueue
$media->save();
}
if(config('media.hls.enabled')) {
VideoHlsPipeline::dispatch($media)->onQueue('mmo');
}
} catch (Exception $e) {
}

Wyświetl plik

@ -0,0 +1,27 @@
<?php
namespace App\Services\Media;
use Storage;
class MediaHlsService
{
public static function allFiles($media)
{
$path = $media->media_path;
if(!$path) { return; }
$parts = explode('/', $path);
$filename = array_pop($parts);
$dir = implode('/', $parts);
[$name, $ext] = explode('.', $filename);
$files = Storage::files($dir);
return collect($files)
->filter(function($p) use($dir, $name) {
return str_starts_with($p, $dir . '/' . $name);
})
->values()
->toArray();
}
}

Wyświetl plik

@ -18,7 +18,7 @@ class MediaService
public static function get($statusId)
{
return Cache::remember(self::CACHE_KEY.$statusId, 86400, function() use($statusId) {
return Cache::remember(self::CACHE_KEY.$statusId, 21600, function() use($statusId) {
$media = Media::whereStatusId($statusId)->orderBy('order')->get();
if(!$media) {
return [];
@ -46,7 +46,8 @@ class MediaService
$media['orientation'],
$media['filter_name'],
$media['filter_class'],
$media['mime']
$media['mime'],
$media['hls_manifest']
);
$media['type'] = $mime ? strtolower($mime[0]) : 'unknown';

Wyświetl plik

@ -4,6 +4,7 @@ namespace App\Transformer\Api;
use App\Media;
use League\Fractal;
use Storage;
class MediaTransformer extends Fractal\TransformerAbstract
{
@ -28,6 +29,10 @@ class MediaTransformer extends Fractal\TransformerAbstract
'blurhash' => $media->blurhash ?? 'U4Rfzst8?bt7ogayj[j[~pfQ9Goe%Mj[WBay'
];
if(config('media.hls.enabled') && $media->hls_transcoded_at != null && $media->hls_path) {
$res['hls_manifest'] = url(Storage::url($media->hls_path));
}
if($media->width && $media->height) {
$res['meta'] = [
'focus' => [

Wyświetl plik

@ -7,86 +7,100 @@ use Illuminate\Support\Str;
class Config {
const CACHE_KEY = 'api:site:configuration:_v0.8';
const CACHE_KEY = 'api:site:configuration:_v0.8';
public static function get() {
return Cache::remember(self::CACHE_KEY, 900, function() {
return [
'version' => config('pixelfed.version'),
'open_registration' => (bool) config_cache('pixelfed.open_registration'),
'uploader' => [
'max_photo_size' => (int) config('pixelfed.max_photo_size'),
'max_caption_length' => (int) config('pixelfed.max_caption_length'),
'max_altext_length' => (int) config('pixelfed.max_altext_length', 150),
'album_limit' => (int) config_cache('pixelfed.max_album_length'),
'image_quality' => (int) config_cache('pixelfed.image_quality'),
public static function get() {
return Cache::remember(self::CACHE_KEY, 900, function() {
$hls = [
'enabled' => config('media.hls.enabled'),
];
if(config('media.hls.enabled')) {
$hls = [
'enabled' => true,
'debug' => (bool) config('media.hls.debug'),
'p2p' => (bool) config('media.hls.p2p'),
'p2p_debug' => (bool) config('media.hls.p2p_debug'),
'tracker' => config('media.hls.tracker'),
'ice' => config('media.hls.ice')
];
}
return [
'version' => config('pixelfed.version'),
'open_registration' => (bool) config_cache('pixelfed.open_registration'),
'uploader' => [
'max_photo_size' => (int) config('pixelfed.max_photo_size'),
'max_caption_length' => (int) config('pixelfed.max_caption_length'),
'max_altext_length' => (int) config('pixelfed.max_altext_length', 150),
'album_limit' => (int) config_cache('pixelfed.max_album_length'),
'image_quality' => (int) config_cache('pixelfed.image_quality'),
'max_collection_length' => (int) config('pixelfed.max_collection_length', 18),
'max_collection_length' => (int) config('pixelfed.max_collection_length', 18),
'optimize_image' => (bool) config('pixelfed.optimize_image'),
'optimize_video' => (bool) config('pixelfed.optimize_video'),
'optimize_image' => (bool) config('pixelfed.optimize_image'),
'optimize_video' => (bool) config('pixelfed.optimize_video'),
'media_types' => config_cache('pixelfed.media_types'),
'mime_types' => config_cache('pixelfed.media_types') ? explode(',', config_cache('pixelfed.media_types')) : [],
'enforce_account_limit' => (bool) config_cache('pixelfed.enforce_account_limit')
],
'media_types' => config_cache('pixelfed.media_types'),
'mime_types' => config_cache('pixelfed.media_types') ? explode(',', config_cache('pixelfed.media_types')) : [],
'enforce_account_limit' => (bool) config_cache('pixelfed.enforce_account_limit')
],
'activitypub' => [
'enabled' => (bool) config_cache('federation.activitypub.enabled'),
'remote_follow' => config('federation.activitypub.remoteFollow')
],
'activitypub' => [
'enabled' => (bool) config_cache('federation.activitypub.enabled'),
'remote_follow' => config('federation.activitypub.remoteFollow')
],
'ab' => config('exp'),
'ab' => config('exp'),
'site' => [
'name' => config_cache('app.name'),
'domain' => config('pixelfed.domain.app'),
'url' => config('app.url'),
'description' => config_cache('app.short_description')
],
'site' => [
'name' => config_cache('app.name'),
'domain' => config('pixelfed.domain.app'),
'url' => config('app.url'),
'description' => config_cache('app.short_description')
],
'account' => [
'max_avatar_size' => config('pixelfed.max_avatar_size'),
'max_bio_length' => config('pixelfed.max_bio_length'),
'max_name_length' => config('pixelfed.max_name_length'),
'min_password_length' => config('pixelfed.min_password_length'),
'max_account_size' => config('pixelfed.max_account_size')
],
'account' => [
'max_avatar_size' => config('pixelfed.max_avatar_size'),
'max_bio_length' => config('pixelfed.max_bio_length'),
'max_name_length' => config('pixelfed.max_name_length'),
'min_password_length' => config('pixelfed.min_password_length'),
'max_account_size' => config('pixelfed.max_account_size')
],
'username' => [
'remote' => [
'formats' => config('instance.username.remote.formats'),
'format' => config('instance.username.remote.format'),
'custom' => config('instance.username.remote.custom')
]
],
'username' => [
'remote' => [
'formats' => config('instance.username.remote.formats'),
'format' => config('instance.username.remote.format'),
'custom' => config('instance.username.remote.custom')
]
],
'features' => [
'timelines' => [
'local' => true,
'network' => (bool) config('federation.network_timeline'),
],
'mobile_apis' => (bool) config_cache('pixelfed.oauth_enabled'),
'stories' => (bool) config_cache('instance.stories.enabled'),
'video' => Str::contains(config_cache('pixelfed.media_types'), 'video/mp4'),
'import' => [
'instagram' => (bool) config_cache('pixelfed.import.instagram.enabled'),
'mastodon' => false,
'pixelfed' => false
],
'label' => [
'covid' => [
'enabled' => (bool) config('instance.label.covid.enabled'),
'org' => config('instance.label.covid.org'),
'url' => config('instance.label.covid.url'),
]
]
]
];
});
}
'features' => [
'timelines' => [
'local' => true,
'network' => (bool) config('federation.network_timeline'),
],
'mobile_apis' => (bool) config_cache('pixelfed.oauth_enabled'),
'stories' => (bool) config_cache('instance.stories.enabled'),
'video' => Str::contains(config_cache('pixelfed.media_types'), 'video/mp4'),
'import' => [
'instagram' => (bool) config_cache('pixelfed.import.instagram.enabled'),
'mastodon' => false,
'pixelfed' => false
],
'label' => [
'covid' => [
'enabled' => (bool) config('instance.label.covid.enabled'),
'org' => config('instance.label.covid.org'),
'url' => config('instance.label.covid.url'),
]
],
'hls' => $hls
]
];
});
}
public static function json() {
return json_encode(self::get(), JSON_FORCE_OBJECT);
}
public static function json() {
return json_encode(self::get(), JSON_FORCE_OBJECT);
}
}

Wyświetl plik

@ -3,8 +3,7 @@
return [
'ffmpeg' => [
'binaries' => env('FFMPEG_BINARIES', 'ffmpeg'),
'threads' => 12, // set to false to disable the default 'threads' filter
'threads' => env('FFMPEG_THREADS', false),
],
'ffprobe' => [
@ -18,4 +17,6 @@ return [
'temporary_files_root' => env('FFMPEG_TEMPORARY_FILES_ROOT', sys_get_temp_dir()),
'temporary_files_encrypted_hls' => env('FFMPEG_TEMPORARY_ENCRYPTED_HLS', env('FFMPEG_TEMPORARY_FILES_ROOT', sys_get_temp_dir())),
'min_hls_version' => env('FFMPEG_MIN_HLS_VERSION', '4.3.0'),
];

Wyświetl plik

@ -22,5 +22,39 @@ return [
'resilient_mode' => env('ALT_PRI_ENABLED', false) || env('ALT_SEC_ENABLED', false),
],
],
'hls' => [
/*
|--------------------------------------------------------------------------
| Enable HLS
|--------------------------------------------------------------------------
|
| Enable optional HLS support, required for video p2p support. Requires FFMPEG
| Disabled by default.
|
*/
'enabled' => env('MEDIA_HLS_ENABLED', false),
'debug' => env('MEDIA_HLS_DEBUG', false),
/*
|--------------------------------------------------------------------------
| Enable Video P2P support
|--------------------------------------------------------------------------
|
| Enable optional video p2p support. Requires FFMPEG + HLS
| Disabled by default.
|
*/
'p2p' => env('MEDIA_HLS_P2P', false),
'p2p_debug' => env('MEDIA_HLS_P2P_DEBUG', false),
'bitrate' => env('MEDIA_HLS_BITRATE', 1000),
'tracker' => env('MEDIA_HLS_P2P_TRACKER', 'wss://tracker.webtorrent.dev'),
'ice' => env('MEDIA_HLS_P2P_ICE_SERVER', 'stun:stun.l.google.com:19302'),
]
];

2081
package-lock.json wygenerowano

Plik diff jest za duży Load Diff

Wyświetl plik

@ -34,9 +34,12 @@
},
"dependencies": {
"@fancyapps/fancybox": "^3.5.7",
"@hcaptcha/vue-hcaptcha": "^1.3.0",
"@peertube/p2p-media-loader-core": "^1.0.14",
"@peertube/p2p-media-loader-hlsjs": "^1.0.14",
"@trevoreyre/autocomplete-vue": "^2.2.0",
"@web3-storage/parse-link-header": "^3.1.0",
"@zip.js/zip.js": "^2.7.14",
"@zip.js/zip.js": "^2.7.24",
"animate.css": "^4.1.0",
"bigpicture": "^2.6.2",
"blurhash": "^1.1.3",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
public/js/admin.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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

2
public/js/direct.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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

Wyświetl plik

@ -1 +0,0 @@
"use strict";(self.webpackChunkpixelfed=self.webpackChunkpixelfed||[]).push([[4028],{58947:(a,t,e)=>{e.r(t),e.d(t,{default:()=>s});const s={components:{drawer:e(42755).default}}},89250:(a,t,e)=>{e.r(t),e.d(t,{default:()=>s});const s={data:function(){return{user:window._sharedData.user}}}},56943:(a,t,e)=>{e.r(t),e.d(t,{render:()=>s,staticRenderFns:()=>n});var s=function(){var a=this,t=a._self._c;return t("div",{staticClass:"container d-flex justify-content-center"},[a._m(0),a._v(" "),t("drawer")],1)},n=[function(){var a=this,t=a._self._c;return t("div",{staticClass:"error-page py-5 my-5",staticStyle:{"max-width":"450px"}},[t("h3",{staticClass:"font-weight-bold"},[a._v("404   Page Not Found")]),a._v(" "),t("p",{staticClass:"lead"},[a._v("The page you are trying to view is not available")]),a._v(" "),t("div",{staticClass:"text-muted"},[t("p",{staticClass:"mb-1"},[a._v("This can happen for a few reasons:")]),a._v(" "),t("ul",[t("li",[a._v("The url is invalid or has a typo")]),a._v(" "),t("li",[a._v("The page has been flagged for review by our automated abuse detection systems")]),a._v(" "),t("li",[a._v("The content may have been deleted")]),a._v(" "),t("li",[a._v("You do not have permission to view this content")])])])])}]},7231:(a,t,e)=>{e.r(t),e.d(t,{render:()=>s,staticRenderFns:()=>n});var s=function(){var a=this,t=a._self._c;return t("div",{staticClass:"app-drawer-component"},[t("div",{staticClass:"mobile-footer-spacer d-block d-sm-none mt-5"}),a._v(" "),t("div",{staticClass:"mobile-footer d-block d-sm-none fixed-bottom"},[t("div",{staticClass:"card card-body rounded-0 px-0 pt-2 pb-3 box-shadow",staticStyle:{"border-top":"1px solid var(--border-color)"}},[t("ul",{staticClass:"nav nav-pills nav-fill d-flex align-items-middle"},[t("li",{staticClass:"nav-item"},[t("router-link",{staticClass:"nav-link text-dark",attrs:{to:"/i/web"}},[t("p",[t("i",{staticClass:"far fa-home fa-lg"})]),a._v(" "),t("p",{staticClass:"nav-link-label"},[t("span",[a._v("Home")])])])],1),a._v(" "),t("li",{staticClass:"nav-item"},[t("router-link",{staticClass:"nav-link text-dark",attrs:{to:"/i/web/timeline/local"}},[t("p",[t("i",{staticClass:"far fa-stream fa-lg"})]),a._v(" "),t("p",{staticClass:"nav-link-label"},[t("span",[a._v("Local")])])])],1),a._v(" "),t("li",{staticClass:"nav-item"},[t("router-link",{staticClass:"nav-link text-dark",attrs:{to:"/i/web/compose"}},[t("p",[t("i",{staticClass:"far fa-plus-circle fa-lg"})]),a._v(" "),t("p",{staticClass:"nav-link-label"},[t("span",[a._v("New")])])])],1),a._v(" "),t("li",{staticClass:"nav-item"},[t("router-link",{staticClass:"nav-link text-dark",attrs:{to:"/i/web/notifications"}},[t("p",[t("i",{staticClass:"far fa-bell fa-lg"})]),a._v(" "),t("p",{staticClass:"nav-link-label"},[t("span",[a._v("Alerts")])])])],1),a._v(" "),t("li",{staticClass:"nav-item"},[t("router-link",{staticClass:"nav-link text-dark",attrs:{to:"/i/web/profile/"+a.user.id}},[t("p",[t("i",{staticClass:"far fa-user fa-lg"})]),a._v(" "),t("p",{staticClass:"nav-link-label"},[t("span",[a._v("Profile")])])])],1)])])])])},n=[]},95433:(a,t,e)=>{e.r(t),e.d(t,{default:()=>l});var s=e(1519),n=e.n(s)()((function(a){return a[1]}));n.push([a.id,".app-drawer-component .nav-link{padding:.5rem .1rem}.app-drawer-component .nav-link.active{background-color:transparent}.app-drawer-component .nav-link.router-link-exact-active{background-color:transparent;color:var(--primary)!important}.app-drawer-component .nav-link p{margin-bottom:0}.app-drawer-component .nav-link-label{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;font-size:10px;font-weight:700;margin-top:0;opacity:.6;text-transform:uppercase}",""]);const l=n},2869:(a,t,e)=>{e.r(t),e.d(t,{default:()=>r});var s=e(93379),n=e.n(s),l=e(95433),i={insert:"head",singleton:!1};n()(l.default,i);const r=l.default.locals||{}},42390:(a,t,e)=>{e.r(t),e.d(t,{default:()=>i});var s=e(33500),n=e(29414),l={};for(const a in n)"default"!==a&&(l[a]=()=>n[a]);e.d(t,l);const i=(0,e(51900).default)(n.default,s.render,s.staticRenderFns,!1,null,null,null).exports},42755:(a,t,e)=>{e.r(t),e.d(t,{default:()=>i});var s=e(87661),n=e(1374),l={};for(const a in n)"default"!==a&&(l[a]=()=>n[a]);e.d(t,l);e(72682);const i=(0,e(51900).default)(n.default,s.render,s.staticRenderFns,!1,null,null,null).exports},29414:(a,t,e)=>{e.r(t),e.d(t,{default:()=>l});var s=e(58947),n={};for(const a in s)"default"!==a&&(n[a]=()=>s[a]);e.d(t,n);const l=s.default},1374:(a,t,e)=>{e.r(t),e.d(t,{default:()=>l});var s=e(89250),n={};for(const a in s)"default"!==a&&(n[a]=()=>s[a]);e.d(t,n);const l=s.default},33500:(a,t,e)=>{e.r(t);var s=e(56943),n={};for(const a in s)"default"!==a&&(n[a]=()=>s[a]);e.d(t,n)},87661:(a,t,e)=>{e.r(t);var s=e(7231),n={};for(const a in s)"default"!==a&&(n[a]=()=>s[a]);e.d(t,n)},72682:(a,t,e)=>{e.r(t);var s=e(2869),n={};for(const a in s)"default"!==a&&(n[a]=()=>s[a]);e.d(t,n)}}]);

Wyświetl plik

@ -0,0 +1 @@
"use strict";(self.webpackChunkpixelfed=self.webpackChunkpixelfed||[]).push([[4028],{62092:(a,t,e)=>{e.r(t),e.d(t,{default:()=>s});const s={components:{drawer:e(42755).default}}},14287:(a,t,e)=>{e.r(t),e.d(t,{default:()=>s});const s={data:function(){return{user:window._sharedData.user}}}},60288:(a,t,e)=>{e.r(t),e.d(t,{render:()=>s,staticRenderFns:()=>n});var s=function(){var a=this,t=a._self._c;return t("div",{staticClass:"container d-flex justify-content-center"},[a._m(0),a._v(" "),t("drawer")],1)},n=[function(){var a=this,t=a._self._c;return t("div",{staticClass:"error-page py-5 my-5",staticStyle:{"max-width":"450px"}},[t("h3",{staticClass:"font-weight-bold"},[a._v("404   Page Not Found")]),a._v(" "),t("p",{staticClass:"lead"},[a._v("The page you are trying to view is not available")]),a._v(" "),t("div",{staticClass:"text-muted"},[t("p",{staticClass:"mb-1"},[a._v("This can happen for a few reasons:")]),a._v(" "),t("ul",[t("li",[a._v("The url is invalid or has a typo")]),a._v(" "),t("li",[a._v("The page has been flagged for review by our automated abuse detection systems")]),a._v(" "),t("li",[a._v("The content may have been deleted")]),a._v(" "),t("li",[a._v("You do not have permission to view this content")])])])])}]},69356:(a,t,e)=>{e.r(t),e.d(t,{render:()=>s,staticRenderFns:()=>n});var s=function(){var a=this,t=a._self._c;return t("div",{staticClass:"app-drawer-component"},[t("div",{staticClass:"mobile-footer-spacer d-block d-sm-none mt-5"}),a._v(" "),t("div",{staticClass:"mobile-footer d-block d-sm-none fixed-bottom"},[t("div",{staticClass:"card card-body rounded-0 px-0 pt-2 pb-3 box-shadow",staticStyle:{"border-top":"1px solid var(--border-color)"}},[t("ul",{staticClass:"nav nav-pills nav-fill d-flex align-items-middle"},[t("li",{staticClass:"nav-item"},[t("router-link",{staticClass:"nav-link text-dark",attrs:{to:"/i/web"}},[t("p",[t("i",{staticClass:"far fa-home fa-lg"})]),a._v(" "),t("p",{staticClass:"nav-link-label"},[t("span",[a._v("Home")])])])],1),a._v(" "),t("li",{staticClass:"nav-item"},[t("router-link",{staticClass:"nav-link text-dark",attrs:{to:"/i/web/timeline/local"}},[t("p",[t("i",{staticClass:"far fa-stream fa-lg"})]),a._v(" "),t("p",{staticClass:"nav-link-label"},[t("span",[a._v("Local")])])])],1),a._v(" "),t("li",{staticClass:"nav-item"},[t("router-link",{staticClass:"nav-link text-dark",attrs:{to:"/i/web/compose"}},[t("p",[t("i",{staticClass:"far fa-plus-circle fa-lg"})]),a._v(" "),t("p",{staticClass:"nav-link-label"},[t("span",[a._v("New")])])])],1),a._v(" "),t("li",{staticClass:"nav-item"},[t("router-link",{staticClass:"nav-link text-dark",attrs:{to:"/i/web/notifications"}},[t("p",[t("i",{staticClass:"far fa-bell fa-lg"})]),a._v(" "),t("p",{staticClass:"nav-link-label"},[t("span",[a._v("Alerts")])])])],1),a._v(" "),t("li",{staticClass:"nav-item"},[t("router-link",{staticClass:"nav-link text-dark",attrs:{to:"/i/web/profile/"+a.user.id}},[t("p",[t("i",{staticClass:"far fa-user fa-lg"})]),a._v(" "),t("p",{staticClass:"nav-link-label"},[t("span",[a._v("Profile")])])])],1)])])])])},n=[]},62869:(a,t,e)=>{e.r(t),e.d(t,{default:()=>l});var s=e(1519),n=e.n(s)()((function(a){return a[1]}));n.push([a.id,".app-drawer-component .nav-link{padding:.5rem .1rem}.app-drawer-component .nav-link.active{background-color:transparent}.app-drawer-component .nav-link.router-link-exact-active{background-color:transparent;color:var(--primary)!important}.app-drawer-component .nav-link p{margin-bottom:0}.app-drawer-component .nav-link-label{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;font-size:10px;font-weight:700;margin-top:0;opacity:.6;text-transform:uppercase}",""]);const l=n},40014:(a,t,e)=>{e.r(t),e.d(t,{default:()=>r});var s=e(93379),n=e.n(s),l=e(62869),i={insert:"head",singleton:!1};n()(l.default,i);const r=l.default.locals||{}},42390:(a,t,e)=>{e.r(t),e.d(t,{default:()=>i});var s=e(94761),n=e(29210),l={};for(const a in n)"default"!==a&&(l[a]=()=>n[a]);e.d(t,l);const i=(0,e(51900).default)(n.default,s.render,s.staticRenderFns,!1,null,null,null).exports},42755:(a,t,e)=>{e.r(t),e.d(t,{default:()=>i});var s=e(73307),n=e(6380),l={};for(const a in n)"default"!==a&&(l[a]=()=>n[a]);e.d(t,l);e(10973);const i=(0,e(51900).default)(n.default,s.render,s.staticRenderFns,!1,null,null,null).exports},29210:(a,t,e)=>{e.r(t),e.d(t,{default:()=>l});var s=e(62092),n={};for(const a in s)"default"!==a&&(n[a]=()=>s[a]);e.d(t,n);const l=s.default},6380:(a,t,e)=>{e.r(t),e.d(t,{default:()=>l});var s=e(14287),n={};for(const a in s)"default"!==a&&(n[a]=()=>s[a]);e.d(t,n);const l=s.default},94761:(a,t,e)=>{e.r(t);var s=e(60288),n={};for(const a in s)"default"!==a&&(n[a]=()=>s[a]);e.d(t,n)},73307:(a,t,e)=>{e.r(t);var s=e(69356),n={};for(const a in s)"default"!==a&&(n[a]=()=>s[a]);e.d(t,n)},10973:(a,t,e)=>{e.r(t);var s=e(40014),n={};for(const a in s)"default"!==a&&(n[a]=()=>s[a]);e.d(t,n)}}]);

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

Wyświetl plik

@ -1 +1 @@
(()=>{"use strict";var e,r,n,o={},t={};function a(e){var r=t[e];if(void 0!==r)return r.exports;var n=t[e]={id:e,loaded:!1,exports:{}};return o[e].call(n.exports,n,n.exports,a),n.loaded=!0,n.exports}a.m=o,e=[],a.O=(r,n,o,t)=>{if(!n){var d=1/0;for(f=0;f<e.length;f++){for(var[n,o,t]=e[f],c=!0,i=0;i<n.length;i++)(!1&t||d>=t)&&Object.keys(a.O).every((e=>a.O[e](n[i])))?n.splice(i--,1):(c=!1,t<d&&(d=t));if(c){e.splice(f--,1);var s=o();void 0!==s&&(r=s)}}return r}t=t||0;for(var f=e.length;f>0&&e[f-1][2]>t;f--)e[f]=e[f-1];e[f]=[n,o,t]},a.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return a.d(r,{a:r}),r},a.d=(e,r)=>{for(var n in r)a.o(r,n)&&!a.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:r[n]})},a.f={},a.e=e=>Promise.all(Object.keys(a.f).reduce(((r,n)=>(a.f[n](e,r),r)),[])),a.u=e=>"js/"+{1084:"profile~followers.bundle",2470:"home.chunk",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",4958:"discover.chunk",4965:"discover~memories.chunk",5865:"post.chunk",6053:"notifications.chunk",6869:"profile.chunk",7019:"discover~hashtag.bundle",8250:"i18n.bundle",8517:"daci.chunk",8600:"changelog.bundle",8625:"profile~following.bundle",8900:"discover~serverfeed.chunk"}[e]+"."+{1084:"f088062414c3b014",2470:"bd623a430a5584c2",2530:"ee5af357937cad2f",2586:"6464688bf5b5ef97",2732:"990c68dfc266b0cf",3351:"909aa0316f43235e",3365:"98e12cf9137ddd87",3623:"6bd4ddbabd979778",4028:"182d0aaa2da9ed23",4958:"56d2d8cfbbecc761",4965:"400f9f019bdb9fdf",5865:"729ca668f46545cb",6053:"bf0c641eb1fd9cde",6869:"029572d9018fc65f",7019:"54f2ac43c55bf328",8250:"4a5ff18de549ac4e",8517:"bfa9e4f459fec835",8600:"c4c82057f9628c72",8625:"57cbb89efa73e324",8900:"fbe31eedcdafc87e"}[e]+".js",a.miniCssF=e=>({138:"css/spa",703:"css/admin",1242:"css/appdark",6170:"css/app",8737:"css/portfolio",9994:"css/landing"}[e]+".css"),a.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),a.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),r={},n="pixelfed:",a.l=(e,o,t,d)=>{if(r[e])r[e].push(o);else{var c,i;if(void 0!==t)for(var s=document.getElementsByTagName("script"),f=0;f<s.length;f++){var l=s[f];if(l.getAttribute("src")==e||l.getAttribute("data-webpack")==n+t){c=l;break}}c||(i=!0,(c=document.createElement("script")).charset="utf-8",c.timeout=120,a.nc&&c.setAttribute("nonce",a.nc),c.setAttribute("data-webpack",n+t),c.src=e),r[e]=[o];var u=(n,o)=>{c.onerror=c.onload=null,clearTimeout(b);var t=r[e];if(delete r[e],c.parentNode&&c.parentNode.removeChild(c),t&&t.forEach((e=>e(o))),n)return n(o)},b=setTimeout(u.bind(null,void 0,{type:"timeout",target:c}),12e4);c.onerror=u.bind(null,c.onerror),c.onload=u.bind(null,c.onload),i&&document.head.appendChild(c)}},a.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),a.p="/",(()=>{var e={8929:0,1242:0,6170:0,8737:0,703:0,9994:0,138:0};a.f.j=(r,n)=>{var o=a.o(e,r)?e[r]:void 0;if(0!==o)if(o)n.push(o[2]);else if(/^(1242|138|6170|703|8737|8929|9994)$/.test(r))e[r]=0;else{var t=new Promise(((n,t)=>o=e[r]=[n,t]));n.push(o[2]=t);var d=a.p+a.u(r),c=new Error;a.l(d,(n=>{if(a.o(e,r)&&(0!==(o=e[r])&&(e[r]=void 0),o)){var t=n&&("load"===n.type?"missing":n.type),d=n&&n.target&&n.target.src;c.message="Loading chunk "+r+" failed.\n("+t+": "+d+")",c.name="ChunkLoadError",c.type=t,c.request=d,o[1](c)}}),"chunk-"+r,r)}},a.O.j=r=>0===e[r];var r=(r,n)=>{var o,t,[d,c,i]=n,s=0;if(d.some((r=>0!==e[r]))){for(o in c)a.o(c,o)&&(a.m[o]=c[o]);if(i)var f=i(a)}for(r&&r(n);s<d.length;s++)t=d[s],a.o(e,t)&&e[t]&&e[t][0](),e[t]=0;return a.O(f)},n=self.webpackChunkpixelfed=self.webpackChunkpixelfed||[];n.forEach(r.bind(null,0)),n.push=r.bind(null,n.push.bind(n))})(),a.nc=void 0})();
(()=>{"use strict";var e,r,n,o={},t={};function d(e){var r=t[e];if(void 0!==r)return r.exports;var n=t[e]={id:e,loaded:!1,exports:{}};return o[e].call(n.exports,n,n.exports,d),n.loaded=!0,n.exports}d.m=o,e=[],d.O=(r,n,o,t)=>{if(!n){var a=1/0;for(l=0;l<e.length;l++){for(var[n,o,t]=e[l],i=!0,c=0;c<n.length;c++)(!1&t||a>=t)&&Object.keys(d.O).every((e=>d.O[e](n[c])))?n.splice(c--,1):(i=!1,t<a&&(a=t));if(i){e.splice(l--,1);var s=o();void 0!==s&&(r=s)}}return r}t=t||0;for(var l=e.length;l>0&&e[l-1][2]>t;l--)e[l]=e[l-1];e[l]=[n,o,t]},d.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return d.d(r,{a:r}),r},d.d=(e,r)=>{for(var n in r)d.o(r,n)&&!d.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:r[n]})},d.f={},d.e=e=>Promise.all(Object.keys(d.f).reduce(((r,n)=>(d.f[n](e,r),r)),[])),d.u=e=>"js/"+{1084:"profile~followers.bundle",2470:"home.chunk",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",4958:"discover.chunk",4965:"discover~memories.chunk",5865:"post.chunk",6053:"notifications.chunk",6869:"profile.chunk",7019:"discover~hashtag.bundle",8250:"i18n.bundle",8517:"daci.chunk",8600:"changelog.bundle",8625:"profile~following.bundle",8900:"discover~serverfeed.chunk"}[e]+"."+{1084:"731f680cfb96563d",2470:"351f55e9d09b6482",2530:"6eab2414b2b16e19",2586:"965eab35620423e5",2732:"15157ff4a6c17cc7",3351:"732c1f76a00d9204",3365:"53a951c5de2d95ac",3623:"02be60ab26503531",4028:"3bbc118159460db6",4958:"9606885dad3c8a99",4965:"ce9cc6446020e9b3",5865:"74f8b1d1954f5d01",6053:"3b92cf46da469de1",6869:"0e5bd852054d6355",7019:"9cfffc517f35044e",8250:"47cbf9f04d955267",8517:"b17a0b11877389d7",8600:"742a06ba0a547120",8625:"3d95796c9f1678dd",8900:"0f2dcc473fdce17e"}[e]+".js",d.miniCssF=e=>({138:"css/spa",703:"css/admin",1242:"css/appdark",6170:"css/app",8737:"css/portfolio",9994:"css/landing"}[e]+".css"),d.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),d.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),r={},n="pixelfed:",d.l=(e,o,t,a)=>{if(r[e])r[e].push(o);else{var i,c;if(void 0!==t)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")==n+t){i=u;break}}i||(c=!0,(i=document.createElement("script")).charset="utf-8",i.timeout=120,d.nc&&i.setAttribute("nonce",d.nc),i.setAttribute("data-webpack",n+t),i.src=e),r[e]=[o];var f=(n,o)=>{i.onerror=i.onload=null,clearTimeout(b);var t=r[e];if(delete r[e],i.parentNode&&i.parentNode.removeChild(i),t&&t.forEach((e=>e(o))),n)return n(o)},b=setTimeout(f.bind(null,void 0,{type:"timeout",target:i}),12e4);i.onerror=f.bind(null,i.onerror),i.onload=f.bind(null,i.onload),c&&document.head.appendChild(i)}},d.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},d.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),d.p="/",(()=>{var e={8929:0,1242:0,6170:0,8737:0,703:0,9994:0,138:0};d.f.j=(r,n)=>{var o=d.o(e,r)?e[r]:void 0;if(0!==o)if(o)n.push(o[2]);else if(/^(1242|138|6170|703|8737|8929|9994)$/.test(r))e[r]=0;else{var t=new Promise(((n,t)=>o=e[r]=[n,t]));n.push(o[2]=t);var a=d.p+d.u(r),i=new Error;d.l(a,(n=>{if(d.o(e,r)&&(0!==(o=e[r])&&(e[r]=void 0),o)){var t=n&&("load"===n.type?"missing":n.type),a=n&&n.target&&n.target.src;i.message="Loading chunk "+r+" failed.\n("+t+": "+a+")",i.name="ChunkLoadError",i.type=t,i.request=a,o[1](i)}}),"chunk-"+r,r)}},d.O.j=r=>0===e[r];var r=(r,n)=>{var o,t,[a,i,c]=n,s=0;if(a.some((r=>0!==e[r]))){for(o in i)d.o(i,o)&&(d.m[o]=i[o]);if(c)var l=c(d)}for(r&&r(n);s<a.length;s++)t=a[s],d.o(e,t)&&e[t]&&e[t][0](),e[t]=0;return d.O(l)},n=self.webpackChunkpixelfed=self.webpackChunkpixelfed||[];n.forEach(r.bind(null,0)),n.push=r.bind(null,n.push.bind(n))})(),d.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

File diff suppressed because one or more lines are too long

Wyświetl plik

@ -1 +1 @@
(self.webpackChunkpixelfed=self.webpackChunkpixelfed||[]).push([[8470],{16289:(t,s,e)=>{"use strict";e.r(s),e.d(s,{default:()=>a});const a={data:function(){return{loaded:!1,showLoadMore:!0,profiles:[],page:1}},beforeMount:function(){this.fetchData()},methods:{fetchData:function(){var t=this;axios.get("/api/pixelfed/v2/discover/profiles",{params:{page:this.page}}).then((function(s){if(0==s.data.length)return t.showLoadMore=!1,void(t.loaded=!0);t.profiles=s.data,t.showLoadMore=8==t.profiles.length,t.loaded=!0}))},prettyCount:function(t){return App.util.format.count(t)},loadMore:function(){this.loaded=!1,this.page++,this.fetchData()},thumbUrl:function(t){return t.media_attachments[0].url}}}},86445:(t,s,e)=>{"use strict";e.r(s),e.d(s,{render:()=>a,staticRenderFns:()=>r});var a=function(){var t=this,s=t._self._c;return s("div",[s("div",{staticClass:"col-12"},[s("p",{staticClass:"font-weight-bold text-lighter text-uppercase"},[t._v("Profiles Directory")]),t._v(" "),t.loaded?s("div",{},[s("div",{staticClass:"row"},[t._l(t.profiles,(function(e,a){return s("div",{staticClass:"col-12 col-md-6 p-1"},[s("div",{staticClass:"card card-body border shadow-none py-2"},[s("div",{staticClass:"media"},[s("a",{attrs:{href:e.url}},[s("img",{staticClass:"rounded-circle border mr-3",attrs:{src:e.avatar,alt:"...",width:"40px",height:"40px"}})]),t._v(" "),s("div",{staticClass:"media-body"},[s("p",{staticClass:"mt-0 mb-0 font-weight-bold"},[s("a",{staticClass:"text-dark",attrs:{href:e.url}},[t._v(t._s(e.username))])]),t._v(" "),s("p",{staticClass:"mb-1 small text-lighter d-flex justify-content-between font-weight-bold"},[s("span",[s("span",[t._v(t._s(t.prettyCount(e.statuses_count)))]),t._v(" POSTS\n\t\t\t\t\t\t\t\t\t")]),t._v(" "),s("span",[s("span",[t._v(t._s(t.prettyCount(e.followers_count)))]),t._v(" FOLLOWERS\n\t\t\t\t\t\t\t\t\t")])]),t._v(" "),s("p",{staticClass:"mb-1"},t._l(e.posts,(function(e,a){return s("span",{key:"profile_posts_"+a,staticClass:"shadow-sm"},[s("a",{staticClass:"text-decoration-none mr-1",attrs:{href:e.url}},[s("img",{staticClass:"border rounded",attrs:{src:t.thumbUrl(e),width:"62.3px",height:"62.3px"}})])])})),0)])])])])})),t._v(" "),t.showLoadMore?s("div",{staticClass:"col-12"},[s("p",{staticClass:"text-center mb-0 pt-3"},[s("button",{staticClass:"btn btn-outline-secondary btn-sm px-4 py-1 font-weight-bold",on:{click:function(s){return t.loadMore()}}},[t._v("Load More")])])]):t._e()],2)]):s("div",[t._m(0)])])])},r=[function(){var t=this._self._c;return t("div",{staticClass:"row"},[t("div",{staticClass:"col-12 d-flex justify-content-center align-items-center"},[t("div",{staticClass:"spinner-border",attrs:{role:"status"}},[t("span",{staticClass:"sr-only"},[this._v("Loading...")])])])])}]},16055:(t,s,e)=>{Vue.component("profile-directory",e(82909).default)},82909:(t,s,e)=>{"use strict";e.r(s),e.d(s,{default:()=>i});var a=e(54500),r=e(97053),o={};for(const t in r)"default"!==t&&(o[t]=()=>r[t]);e.d(s,o);const i=(0,e(51900).default)(r.default,a.render,a.staticRenderFns,!1,null,"7b3eea1c",null).exports},97053:(t,s,e)=>{"use strict";e.r(s),e.d(s,{default:()=>o});var a=e(16289),r={};for(const t in a)"default"!==t&&(r[t]=()=>a[t]);e.d(s,r);const o=a.default},54500:(t,s,e)=>{"use strict";e.r(s);var a=e(86445),r={};for(const t in a)"default"!==t&&(r[t]=()=>a[t]);e.d(s,r)}},t=>{t.O(0,[8898],(()=>{return s=16055,t(t.s=s);var s}));t.O()}]);
(self.webpackChunkpixelfed=self.webpackChunkpixelfed||[]).push([[8470],{44180:(t,s,e)=>{"use strict";e.r(s),e.d(s,{default:()=>a});const a={data:function(){return{loaded:!1,showLoadMore:!0,profiles:[],page:1}},beforeMount:function(){this.fetchData()},methods:{fetchData:function(){var t=this;axios.get("/api/pixelfed/v2/discover/profiles",{params:{page:this.page}}).then((function(s){if(0==s.data.length)return t.showLoadMore=!1,void(t.loaded=!0);t.profiles=s.data,t.showLoadMore=8==t.profiles.length,t.loaded=!0}))},prettyCount:function(t){return App.util.format.count(t)},loadMore:function(){this.loaded=!1,this.page++,this.fetchData()},thumbUrl:function(t){return t.media_attachments[0].url}}}},57900:(t,s,e)=>{"use strict";e.r(s),e.d(s,{render:()=>a,staticRenderFns:()=>r});var a=function(){var t=this,s=t._self._c;return s("div",[s("div",{staticClass:"col-12"},[s("p",{staticClass:"font-weight-bold text-lighter text-uppercase"},[t._v("Profiles Directory")]),t._v(" "),t.loaded?s("div",{},[s("div",{staticClass:"row"},[t._l(t.profiles,(function(e,a){return s("div",{staticClass:"col-12 col-md-6 p-1"},[s("div",{staticClass:"card card-body border shadow-none py-2"},[s("div",{staticClass:"media"},[s("a",{attrs:{href:e.url}},[s("img",{staticClass:"rounded-circle border mr-3",attrs:{src:e.avatar,alt:"...",width:"40px",height:"40px"}})]),t._v(" "),s("div",{staticClass:"media-body"},[s("p",{staticClass:"mt-0 mb-0 font-weight-bold"},[s("a",{staticClass:"text-dark",attrs:{href:e.url}},[t._v(t._s(e.username))])]),t._v(" "),s("p",{staticClass:"mb-1 small text-lighter d-flex justify-content-between font-weight-bold"},[s("span",[s("span",[t._v(t._s(t.prettyCount(e.statuses_count)))]),t._v(" POSTS\n\t\t\t\t\t\t\t\t\t")]),t._v(" "),s("span",[s("span",[t._v(t._s(t.prettyCount(e.followers_count)))]),t._v(" FOLLOWERS\n\t\t\t\t\t\t\t\t\t")])]),t._v(" "),s("p",{staticClass:"mb-1"},t._l(e.posts,(function(e,a){return s("span",{key:"profile_posts_"+a,staticClass:"shadow-sm"},[s("a",{staticClass:"text-decoration-none mr-1",attrs:{href:e.url}},[s("img",{staticClass:"border rounded",attrs:{src:t.thumbUrl(e),width:"62.3px",height:"62.3px"}})])])})),0)])])])])})),t._v(" "),t.showLoadMore?s("div",{staticClass:"col-12"},[s("p",{staticClass:"text-center mb-0 pt-3"},[s("button",{staticClass:"btn btn-outline-secondary btn-sm px-4 py-1 font-weight-bold",on:{click:function(s){return t.loadMore()}}},[t._v("Load More")])])]):t._e()],2)]):s("div",[t._m(0)])])])},r=[function(){var t=this._self._c;return t("div",{staticClass:"row"},[t("div",{staticClass:"col-12 d-flex justify-content-center align-items-center"},[t("div",{staticClass:"spinner-border",attrs:{role:"status"}},[t("span",{staticClass:"sr-only"},[this._v("Loading...")])])])])}]},16055:(t,s,e)=>{Vue.component("profile-directory",e(82909).default)},82909:(t,s,e)=>{"use strict";e.r(s),e.d(s,{default:()=>i});var a=e(40422),r=e(23366),o={};for(const t in r)"default"!==t&&(o[t]=()=>r[t]);e.d(s,o);const i=(0,e(51900).default)(r.default,a.render,a.staticRenderFns,!1,null,"7b3eea1c",null).exports},23366:(t,s,e)=>{"use strict";e.r(s),e.d(s,{default:()=>o});var a=e(44180),r={};for(const t in a)"default"!==t&&(r[t]=()=>a[t]);e.d(s,r);const o=a.default},40422:(t,s,e)=>{"use strict";e.r(s);var a=e(57900),r={};for(const t in a)"default"!==t&&(r[t]=()=>a[t]);e.d(s,r)}},t=>{t.O(0,[8898],(()=>{return s=16055,t(t.s=s);var s}));t.O()}]);

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

2
public/js/search.js vendored

File diff suppressed because one or more lines are too long

2
public/js/spa.js vendored

File diff suppressed because one or more lines are too long

2
public/js/status.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
public/js/vendor.js vendored

File diff suppressed because one or more lines are too long

Wyświetl plik

@ -31,13 +31,13 @@
*/
/*!
* Cropper.js v1.5.13
* Cropper.js v1.6.1
* https://fengyuanchen.github.io/cropperjs
*
* Copyright 2015-present Chen Fengyuan
* Released under the MIT license
*
* Date: 2022-11-20T05:30:46.114Z
* Date: 2023-09-17T03:44:19.860Z
*/
/*!
@ -56,6 +56,20 @@
* Licensed under GPL 3.
*/
/*!
* The buffer module from node.js, for the browser.
*
* @author Feross Aboukhadijeh <http://feross.org>
* @license MIT
*/
/*!
* The buffer module from node.js, for the browser.
*
* @author Feross Aboukhadijeh <https://feross.org>
* @license MIT
*/
/*!
* Vue.js v2.7.14
* (c) 2014-2022 Evan You
@ -63,14 +77,14 @@
*/
/*!
* jQuery JavaScript Library v3.7.0
* jQuery JavaScript Library v3.7.1
* https://jquery.com/
*
* Copyright OpenJS Foundation and other contributors
* Released under the MIT license
* https://jquery.org/license
*
* Date: 2023-05-11T18:29Z
* Date: 2023-08-28T13:37Z
*/
/*!
@ -143,6 +157,18 @@ and limitations under the License.
/*! https://mths.be/punycode v1.4.1 by @mathias */
/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
/*! queue-microtask. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
/*! run-parallel. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
/*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
/*! simple-peer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
/*! simple-websocket. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
/**
* vue-class-component v7.2.3
* (c) 2015-present Evan You
@ -158,6 +184,23 @@ and limitations under the License.
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
*/
/**
* @license Apache-2.0
* Copyright 2018 Novage LLC.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* filesize
*

Wyświetl plik

@ -1,55 +1,55 @@
{
"/js/app.js": "/js/app.js?id=be0383dc776c5fcdd934c2a68a19db1d",
"/js/activity.js": "/js/activity.js?id=0c9912fde1a026e6ebe7f5b6ba9eb41c",
"/js/activity.js": "/js/activity.js?id=bab5c110c78fbf44118ba9d43de424e3",
"/js/components.js": "/js/components.js?id=9f8d82f1340d91a3be0910a1ae0557a1",
"/js/discover.js": "/js/discover.js?id=32fa894cb63cfe6051bcb20f330bc662",
"/js/profile.js": "/js/profile.js?id=faa0598f99ba6cb8bfa72e755281deb3",
"/js/status.js": "/js/status.js?id=f818f7f9c6a38414da2a9b7d61022be9",
"/js/timeline.js": "/js/timeline.js?id=e19b03e07455dd39204cea6344020283",
"/js/compose.js": "/js/compose.js?id=cd2d7041e5c178b8ca40aecbefac69ed",
"/js/compose-classic.js": "/js/compose-classic.js?id=359aeeb12406e705f6afd9fb86d09acb",
"/js/search.js": "/js/search.js?id=ee5e65e5bb0d78ce8b7e77b36605ab60",
"/js/developers.js": "/js/developers.js?id=8a4578e14108dcd931944610c8f5e843",
"/js/hashtag.js": "/js/hashtag.js?id=49786c1c8c69711da2f15bcdc7fa26a1",
"/js/collectioncompose.js": "/js/collectioncompose.js?id=1e99af77f36f6bd32a086dcb00b051c9",
"/js/collections.js": "/js/collections.js?id=40b8835deabe97b84fc59f8bded9b1ea",
"/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=529801d7a4eec7b0a30f97d1941a8dee",
"/js/spa.js": "/js/spa.js?id=a338b41887a4baadd731f153f2d4f215",
"/js/stories.js": "/js/stories.js?id=4db94699502e85543192865879bece7d",
"/js/portfolio.js": "/js/portfolio.js?id=646ebcbb4cab1dc0942dde3f8126940d",
"/js/account-import.js": "/js/account-import.js?id=00ea9b73c8e17dff27e4a7767d9553d7",
"/js/admin_invite.js": "/js/admin_invite.js?id=307a53250701e3b12164af9495e88447",
"/js/landing.js": "/js/landing.js?id=e0cd637b653c19ed9db93950602cfbab",
"/js/remote_auth.js": "/js/remote_auth.js?id=0840f85f648319858b72c299b8c51f9e",
"/js/manifest.js": "/js/manifest.js?id=9e74c2381399d1777d5e43f647b53d5b",
"/js/home.chunk.bd623a430a5584c2.js": "/js/home.chunk.bd623a430a5584c2.js?id=92e89d40bac4f4cda7f7ab62470bc46d",
"/js/compose.chunk.6464688bf5b5ef97.js": "/js/compose.chunk.6464688bf5b5ef97.js?id=45753d769a16276c2d3ad8d7d6bf3e88",
"/js/post.chunk.729ca668f46545cb.js": "/js/post.chunk.729ca668f46545cb.js?id=fe886fd2acd959b0afb6f64f752dfb3b",
"/js/profile.chunk.029572d9018fc65f.js": "/js/profile.chunk.029572d9018fc65f.js?id=1f010c37345d15e1a55f4f0f6700ff9c",
"/js/discover~memories.chunk.400f9f019bdb9fdf.js": "/js/discover~memories.chunk.400f9f019bdb9fdf.js?id=711043fa1b045b7b4a5163dfc2b9a9d2",
"/js/discover~myhashtags.chunk.ee5af357937cad2f.js": "/js/discover~myhashtags.chunk.ee5af357937cad2f.js?id=5fca6e01d5cbed3dce27cd7f5dc81a12",
"/js/daci.chunk.bfa9e4f459fec835.js": "/js/daci.chunk.bfa9e4f459fec835.js?id=a7a5281b3ddde5b5a6308dc6963acf42",
"/js/discover~findfriends.chunk.6bd4ddbabd979778.js": "/js/discover~findfriends.chunk.6bd4ddbabd979778.js?id=57a85190564956d681151b00dd68a08d",
"/js/discover~serverfeed.chunk.fbe31eedcdafc87e.js": "/js/discover~serverfeed.chunk.fbe31eedcdafc87e.js?id=f1b19651bb66cb2be1a99e372f734cdf",
"/js/discover~settings.chunk.909aa0316f43235e.js": "/js/discover~settings.chunk.909aa0316f43235e.js?id=83e6390aca1a7a07a05694aecccb7942",
"/js/discover.chunk.56d2d8cfbbecc761.js": "/js/discover.chunk.56d2d8cfbbecc761.js?id=25a401188e2fd2a43dec8011d9d62044",
"/js/notifications.chunk.bf0c641eb1fd9cde.js": "/js/notifications.chunk.bf0c641eb1fd9cde.js?id=5a6628e276da9c85244770910f817c0d",
"/js/dms.chunk.98e12cf9137ddd87.js": "/js/dms.chunk.98e12cf9137ddd87.js?id=527795bd736f56ff7d0addb623f0d60b",
"/js/dms~message.chunk.990c68dfc266b0cf.js": "/js/dms~message.chunk.990c68dfc266b0cf.js?id=859b1a07aa91358469143a19505f88c9",
"/js/profile~followers.bundle.f088062414c3b014.js": "/js/profile~followers.bundle.f088062414c3b014.js?id=dc50b57aa36b027c3f5a81efe9525bf2",
"/js/profile~following.bundle.57cbb89efa73e324.js": "/js/profile~following.bundle.57cbb89efa73e324.js?id=59b6dd4955ea43a1c3b116c3c3241993",
"/js/discover~hashtag.bundle.54f2ac43c55bf328.js": "/js/discover~hashtag.bundle.54f2ac43c55bf328.js?id=66ab49a4a126561aad7748163ae19a3f",
"/js/error404.bundle.182d0aaa2da9ed23.js": "/js/error404.bundle.182d0aaa2da9ed23.js?id=a5c557f4d707537aa3f023a0786dfeba",
"/js/i18n.bundle.4a5ff18de549ac4e.js": "/js/i18n.bundle.4a5ff18de549ac4e.js?id=16eb44f6fc379527bfdab1b40a067289",
"/js/changelog.bundle.c4c82057f9628c72.js": "/js/changelog.bundle.c4c82057f9628c72.js?id=d4ca9ce3642f26351e3f6049e4737ba0",
"/js/discover.js": "/js/discover.js?id=789db642d4214d69b245210243bfddd1",
"/js/profile.js": "/js/profile.js?id=ff5ebfe2c05af42a90710184b4a77539",
"/js/status.js": "/js/status.js?id=28214c81b6ef1b443735edb12a3e2af3",
"/js/timeline.js": "/js/timeline.js?id=6af047689b6d4871c816eb9bbd258d6c",
"/js/compose.js": "/js/compose.js?id=b57ac94e8e497e2a45f0353cc49aee5b",
"/js/compose-classic.js": "/js/compose-classic.js?id=6a1e3218c8d3753687e01aeaad9362c9",
"/js/search.js": "/js/search.js?id=4c0e6f5e1b7f43de760c28143605a161",
"/js/developers.js": "/js/developers.js?id=5c04c9c265a39ff23dd395fc56a0eada",
"/js/hashtag.js": "/js/hashtag.js?id=ede3503b82bd2c3dc031cb1a4f70320d",
"/js/collectioncompose.js": "/js/collectioncompose.js?id=4ce940e158d15205ad480821d3d8cd0c",
"/js/collections.js": "/js/collections.js?id=b82669dac1dc1a86c3c33e4ba4bc575a",
"/js/profile-directory.js": "/js/profile-directory.js?id=9b8a56ca460ece9bcd0dcfc4e5d7fa2b",
"/js/story-compose.js": "/js/story-compose.js?id=08a03cf5642c4dcfec5ad2ef78f83c00",
"/js/direct.js": "/js/direct.js?id=74c2962c91cfa3817126b093c3e8112d",
"/js/admin.js": "/js/admin.js?id=595d4b9958efa0ddbfde64af285fe365",
"/js/spa.js": "/js/spa.js?id=3d4942f9a9920995110f87454f9a5979",
"/js/stories.js": "/js/stories.js?id=709b3201264dd2e3776f03ec3393d6b4",
"/js/portfolio.js": "/js/portfolio.js?id=f44a3a87fee04698b55d91a4231fcb8f",
"/js/account-import.js": "/js/account-import.js?id=fe788ad033b51af54f93f6c7b4eb912b",
"/js/admin_invite.js": "/js/admin_invite.js?id=285b7aab611b66b12e16fb95c5cd6a24",
"/js/landing.js": "/js/landing.js?id=0b4df98090afe60d42a25fae96b70a69",
"/js/remote_auth.js": "/js/remote_auth.js?id=8a261c63271e4f126bc259ca94fe691c",
"/js/manifest.js": "/js/manifest.js?id=57032dfd7b47112c377e9e24cce856f4",
"/js/home.chunk.351f55e9d09b6482.js": "/js/home.chunk.351f55e9d09b6482.js?id=78bec7e00db7fa42970b7fee6ae42fc8",
"/js/compose.chunk.965eab35620423e5.js": "/js/compose.chunk.965eab35620423e5.js?id=a1962c16057b41d2547c5974111766bf",
"/js/post.chunk.74f8b1d1954f5d01.js": "/js/post.chunk.74f8b1d1954f5d01.js?id=a7cd3ee72924d3d8b81044e63bf48755",
"/js/profile.chunk.0e5bd852054d6355.js": "/js/profile.chunk.0e5bd852054d6355.js?id=c79db9a7ed9e593c2565f6fe2647ddaa",
"/js/discover~memories.chunk.ce9cc6446020e9b3.js": "/js/discover~memories.chunk.ce9cc6446020e9b3.js?id=05823cac888d03c4a02db391f0497207",
"/js/discover~myhashtags.chunk.6eab2414b2b16e19.js": "/js/discover~myhashtags.chunk.6eab2414b2b16e19.js?id=3296235c4dfc2b53ec12fa3efd6b2853",
"/js/daci.chunk.b17a0b11877389d7.js": "/js/daci.chunk.b17a0b11877389d7.js?id=1c6970aaeedd8cd3fdbaed3f811275d5",
"/js/discover~findfriends.chunk.02be60ab26503531.js": "/js/discover~findfriends.chunk.02be60ab26503531.js?id=9209716c69387daba81d325b8b4036ed",
"/js/discover~serverfeed.chunk.0f2dcc473fdce17e.js": "/js/discover~serverfeed.chunk.0f2dcc473fdce17e.js?id=85fb14dec99be1da2253de939d71ac07",
"/js/discover~settings.chunk.732c1f76a00d9204.js": "/js/discover~settings.chunk.732c1f76a00d9204.js?id=269715e328ff4e8806ae5313141bfba2",
"/js/discover.chunk.9606885dad3c8a99.js": "/js/discover.chunk.9606885dad3c8a99.js?id=861905f74c741b4ba0adea34a6fd1755",
"/js/notifications.chunk.3b92cf46da469de1.js": "/js/notifications.chunk.3b92cf46da469de1.js?id=ce1e415ef9e593daa8fc8ca24c39ae5d",
"/js/dms.chunk.53a951c5de2d95ac.js": "/js/dms.chunk.53a951c5de2d95ac.js?id=533dabb38bd88ce40224b262de5657ca",
"/js/dms~message.chunk.15157ff4a6c17cc7.js": "/js/dms~message.chunk.15157ff4a6c17cc7.js?id=24a896bd3e1ae7ad95eb84ffed03897b",
"/js/profile~followers.bundle.731f680cfb96563d.js": "/js/profile~followers.bundle.731f680cfb96563d.js?id=51a86ce073dcc37182ad95690d3e4150",
"/js/profile~following.bundle.3d95796c9f1678dd.js": "/js/profile~following.bundle.3d95796c9f1678dd.js?id=fab18cec2854cbe0bedeff75a8cd72d7",
"/js/discover~hashtag.bundle.9cfffc517f35044e.js": "/js/discover~hashtag.bundle.9cfffc517f35044e.js?id=09cc057075bddf54f6d27a3d1325956e",
"/js/error404.bundle.3bbc118159460db6.js": "/js/error404.bundle.3bbc118159460db6.js?id=93a2596acb6a7aca829217405e29cf3c",
"/js/i18n.bundle.47cbf9f04d955267.js": "/js/i18n.bundle.47cbf9f04d955267.js?id=6c2e24f203d5b9ff4e21ee7bb614c0d8",
"/js/changelog.bundle.742a06ba0a547120.js": "/js/changelog.bundle.742a06ba0a547120.js?id=e7fed759d5bb60a805e069b0e628a00e",
"/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=0a66549bf79b75a0ca8cb83d11a4e2f4",
"/css/landing.css": "/css/landing.css?id=589f3fa192867727925921b0f68ce022",
"/css/spa.css": "/css/spa.css?id=1bdfa6eb676f51cb5931729abfa6dfd8",
"/js/vendor.js": "/js/vendor.js?id=a0cc6867663084472494dceda20c3392"
"/js/vendor.js": "/js/vendor.js?id=aa78e65108a1408200df9d23217f0aca"
}

Wyświetl plik

@ -12,7 +12,7 @@
</div>
<div v-else-if="status.pf_type === 'video'" class="w-100">
<video-presenter :status="status" v-on:togglecw="status.sensitive = false"></video-presenter>
<video-player :status="status" :fixedHeight="fixedHeight" v-on:togglecw="status.sensitive = false" />
</div>
<div v-else-if="status.pf_type === 'photo:album'" class="w-100">
@ -108,27 +108,11 @@
</div>
</div>
<template v-else-if="status.pf_type === 'video'">
<div v-if="status.sensitive == true" class="content-label-wrapper">
<div class="text-light content-label">
<p class="text-center">
<i class="far fa-eye-slash fa-2x"></i>
</p>
<p class="h4 font-weight-bold text-center">
Sensitive Content
</p>
<p class="text-center py-2 content-label-text">
{{ status.spoiler_text ? status.spoiler_text : 'This post may contain sensitive content.'}}
</p>
<p class="mb-0">
<button @click="status.sensitive = false" class="btn btn-outline-light btn-block btn-sm font-weight-bold">See Post</button>
</p>
</div>
</div>
<video v-else class="card-img-top shadow" :class="{ fixedHeight: fixedHeight }" style="border-radius:15px;object-fit: contain;background-color: #000;" controls :poster="getPoster(status)">
<source :src="status.media_attachments[0].url" :type="status.media_attachments[0].mime">
</video>
</template>
<video-player
v-else-if="status.pf_type === 'video'"
:status="status"
:fixedHeight="fixedHeight"
/>
<div v-else-if="status.pf_type === 'photo:album'" class="card-img-top shadow" style="border-radius: 15px;">
<photo-album-presenter :status="status" v-on:lightbox="toggleLightbox" v-on:togglecw="toggleContentWarning()" style="border-radius:15px !important;object-fit: contain;background-color: #000;overflow: hidden;" :class="{ fixedHeight: fixedHeight }"/>
@ -185,12 +169,14 @@
<script type="text/javascript">
import BigPicture from 'bigpicture';
import ReadMore from './ReadMore.vue';
import VideoPlayer from './../../presenter/VideoPlayer.vue';
export default {
props: ['status'],
components: {
"read-more": ReadMore,
"video-player": VideoPlayer
},
data() {

Wyświetl plik

@ -0,0 +1,198 @@
<template>
<div>
<div v-if="status.sensitive == true" class="content-label-wrapper">
<div class="text-light content-label">
<p class="text-center">
<i class="far fa-eye-slash fa-2x"></i>
</p>
<p class="h4 font-weight-bold text-center">
Sensitive Content
</p>
<p class="text-center py-2 content-label-text">
{{ status.spoiler_text ? status.spoiler_text : 'This post may contain sensitive content.'}}
</p>
<p class="mb-0">
<button @click="status.sensitive = false" class="btn btn-outline-light btn-block btn-sm font-weight-bold">See Post</button>
</p>
</div>
</div>
<template v-else>
<div v-if="!shouldPlay" class="content-label-wrapper" :style="{ background: `linear-gradient(rgba(0, 0, 0, 0.2),rgba(0, 0, 0, 0.8)),url(${getPoster(status)})`, backgroundSize: 'cover'}">
<div class="text-light content-label">
<p class="mb-0">
<button @click.prevent="handleShouldPlay" class="btn btn-link btn-block btn-sm font-weight-bold">
<i class="fas fa-play fa-5x text-white"></i>
</button>
</p>
</div>
</div>
<template v-else>
<video v-if="hasHls" ref="video" :class="{ fixedHeight: fixedHeight }" style="margin:0" playsinline controls autoplay="false" :poster="getPoster(status)">
</video>
<video v-else class="card-img-top shadow" :class="{ fixedHeight: fixedHeight }" style="border-radius:15px;object-fit: contain;background-color: #000;" autoplay="false" controls :poster="getPoster(status)">
<source :src="status.media_attachments[0].url" :type="status.media_attachments[0].mime">
</video>
</template>
</template>
</div>
</template>
<script type="text/javascript">
import Hls from 'hls.js';
import "plyr/dist/plyr.css";
import Plyr from 'plyr';
import { p2pml } from '@peertube/p2p-media-loader-core'
import { Engine, initHlsJsPlayer } from '@peertube/p2p-media-loader-hlsjs'
export default {
props: ['status', 'fixedHeight'],
data() {
return {
shouldPlay: false,
hasHls: undefined,
hlsConfig: window.App.config.features.hls,
liveSyncDurationCount: 7,
isHlsSupported: false,
isP2PSupported: false,
engine: undefined,
}
},
mounted() {
this.$nextTick(() => {
this.init();
})
},
methods: {
handleShouldPlay(){
this.shouldPlay = true;
this.isHlsSupported = this.hlsConfig.enabled && Hls.isSupported();
this.isP2PSupported = this.hlsConfig.enabled && this.hlsConfig.p2p && Engine.isSupported();
this.$nextTick(() => {
this.init();
})
},
init() {
if(!this.status.sensitive && this.status.media_attachments[0]?.hls_manifest && this.isHlsSupported) {
this.hasHls = true;
this.$nextTick(() => {
this.initHls();
})
} else {
this.hasHls = false;
}
},
initHls() {
let loader;
if(this.isP2PSupported) {
const config = {
loader: {
trackerAnnounce: [this.hlsConfig.tracker],
rtcConfig: {
iceServers: [
{
urls: [this.hlsConfig.ice]
}
],
}
}
};
var engine = new Engine(config);
if(this.hlsConfig.p2p_debug) {
engine.on("peer_connect", peer => console.log("peer_connect", peer.id, peer.remoteAddress));
engine.on("peer_close", peerId => console.log("peer_close", peerId));
engine.on("segment_loaded", (segment, peerId) => console.log("segment_loaded from", peerId ? `peer ${peerId}` : "HTTP", segment.url));
}
loader = engine.createLoaderClass();
} else {
loader = Hls.DefaultConfig.loader;
}
const video = this.$refs.video;
const source = this.status.media_attachments[0].hls_manifest;
const player = new Plyr(video, {
captions: {
active: true,
update: true,
},
});
const hls = new Hls({
liveSyncDurationCount: this.liveSyncDurationCount,
loader: loader,
});
let self = this;
initHlsJsPlayer(hls);
hls.loadSource(source);
hls.attachMedia(video);
hls.on(Hls.Events.MANIFEST_PARSED, function(event, data) {
if(this.hlsConfig.debug) {
console.log(event);
console.log(data);
}
const defaultOptions = {};
const availableQualities = hls.levels.map((l) => l.height)
if(this.hlsConfig.debug) {
console.log(availableQualities);
}
availableQualities.unshift(0);
defaultOptions.quality = {
default: 0,
options: availableQualities,
forced: true,
onChange: (e) => self.updateQuality(e),
}
defaultOptions.i18n = {
qualityLabel: {
0: 'Auto',
},
}
hls.on(Hls.Events.LEVEL_SWITCHED, function(event, data) {
var span = document.querySelector(".plyr__menu__container [data-plyr='quality'][value='0'] span")
if (hls.autoLevelEnabled) {
span.innerHTML = `Auto (${hls.levels[data.level].height}p)`
} else {
span.innerHTML = `Auto`
}
})
var player = new Plyr(video, defaultOptions);
});
},
updateQuality(newQuality) {
if (newQuality === 0) {
window.hls.currentLevel = -1;
} else {
window.hls.levels.forEach((level, levelIndex) => {
if (level.height === newQuality) {
if(this.hlsConfig.debug) {
console.log("Found quality match with " + newQuality);
}
window.hls.currentLevel = levelIndex;
}
});
}
},
getPoster(status) {
let url = status.media_attachments[0].preview_url;
if(url.endsWith('no-preview.jpg') || url.endsWith('no-preview.png')) {
return;
}
return url;
}
}
}
</script>

Wyświetl plik

@ -0,0 +1,800 @@
<template>
<div class="card-body">
<p class="lead text-center font-weight-bold">Sign-in with Mastodon</p>
<hr>
<template v-if="step === 1">
<div class="wrapper-mh">
<div class="flex-grow-1">
<p class="text-dark">Hello {{ initialData['_webfinger'] }},</p>
<p class="lead font-weight-bold">Welcome to Pixelfed!</p>
<p>You are moments away from joining our vibrant photo and video focused community with members from around the world.</p>
</div>
<p class="text-xs text-lighter">Your Mastodon account <strong>avatar</strong>, <strong>bio</strong>, <strong>display name</strong>, <strong>followed accounts</strong> and <strong>username</strong> will be imported to speed up the sign-up process. We will never post on your behalf, we only access your public profile data (avatar, bio, display name, followed accounts and username).</p>
</div>
</template>
<template v-else-if="step === 2">
<div class="wrapper-mh">
<div class="pt-3">
<div class="form-group has-float-label">
<input class="form-control form-control-lg" id="f_username" aria-describedby="f_username_help" v-model="username" autofocus/>
<label for="f_username">Username</label>
<p v-if="validUsername && !usernameError" id="f_username_help" class="text-xs text-success font-weight-bold mt-1 mb-0">Available</p>
<p v-else-if="!validUsername && !usernameError" id="f_username_help" class="text-xs text-danger font-weight-bold mt-1 mb-0">Username taken</p>
<p v-else-if="usernameError" id="f_username_help" class="text-xs text-danger font-weight-bold mt-1 mb-0">{{ usernameError }}</p>
</div>
</div>
<div class="pt-3">
<p class="text-sm font-weight-bold mb-1">Avatar</p>
<div class="border rounded-lg p-3 d-flex align-items-center justify-content-between gap-1">
<img v-if="form.importAvatar" :src="initialData.avatar" width="40" height="40" class="rounded-circle" />
<img v-else src="/storage/avatars/default.jpg" width="40" height="40" class="rounded-circle" />
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" id="customCheck1" v-model="form.importAvatar">
<label class="custom-control-label text-xs font-weight-bold" style="line-height: 24px;" for="customCheck1">Import my Mastodon avatar</label>
</div>
</div>
</div>
</div>
</template>
<template v-else-if="step === 3">
<div class="wrapper-mh">
<div class="pt-3">
<div class="form-group has-float-label">
<input class="form-control form-control-lg" id="f_name" aria-describedby="f_name_help" v-model="form.display_name" />
<label for="f_name">Display Name</label>
<div id="f_name_help" class="text-xs text-muted mt-1">Your display name, shown on your profile. You can change this later.</div>
</div>
</div>
<div class="pt-3">
<div class="form-group has-float-label">
<textarea class="form-control" id="f_bio" aria-describedby="f_bio_help" rows="5" v-model="form.bio"></textarea>
<label for="f_bio">Bio</label>
<div id="f_bio_help" class="text-xs text-muted mt-1 d-flex justify-content-between align-items-center">
<div>Describe yourself, you can change this later.</div>
<div>{{ form.bio ? form.bio.length : 0 }}/500</div>
</div>
</div>
</div>
</div>
</template>
<template v-else-if="step === 4">
<div class="wrapper-mh">
<div class="pt-3">
<div class="d-flex align-items-center justify-content-between mb-3">
<div>
<p class="font-weight-bold mb-0">Import accounts you follow</p>
<p class="text-muted text-xs mb-0">You can skip this step and follow accounts later</p>
</div>
<div style="min-width: 100px;text-align:right;">
<p v-if="following && selectedFollowing && following.length == selectedFollowing.length" class="mb-0"><a class="font-weight-bold text-xs text-danger" href="#" @click.prevent="handleFollowerUnselectAll()">Unselect All</a></p>
<p v-else class="mb-0"><a class="font-weight-bold text-xs" href="#" @click.prevent="handleFollowerSelectAll()">Select All</a></p>
</div>
</div>
<div v-if="!followingFetched" class="d-flex align-items-center justify-content-center limit-h">
<div class="w-100">
<instagram-loader></instagram-loader>
</div>
</div>
<div v-else class="list-group limit-h">
<div v-for="(account, idx) in following" class="list-group-item">
<div class="d-flex align-items-center" style="gap:8px;">
<div class="d-flex align-items-center" style="gap:5px;">
<div class="custom-control custom-checkbox">
<input
type="checkbox"
class="custom-control-input"
:value="account.url"
:id="'fac' + idx"
v-model="selectedFollowing"
@change="handleFollower($event, account)">
<label class="custom-control-label" :for="'fac' + idx"></label>
</div>
<img v-if="account.avatar" :src="account.avatar" width="34" height="34" class="rounded-circle" />
<img v-else src="/storage/avatars/default.jpg" width="34" height="34" class="rounded-circle" />
</div>
<div style="max-width: 70%">
<p class="font-weight-bold mb-0 text-truncate">&commat;{{account.username}}</p>
<p class="text-xs text-lighter mb-0 text-truncate">{{account.url.replace('https://', '')}}</p>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<template v-else-if="step === 5">
<div class="wrapper-mh">
<div class="pt-3">
<div class="pb-3">
<p class="font-weight-bold mb-0">We need a bit more info</p>
<p class="text-xs text-muted">Enter your email so you recover access to your account in the future</p>
</div>
<div class="form-group has-float-label">
<input class="form-control" id="f_email" aria-describedby="f_email_help" v-model="email" autofocus="autofocus" />
<label for="f_email">Email address</label>
<p v-if="email && validEmail && !emailError" id="f_email_help" class="text-xs text-success font-weight-bold mt-1 mb-0">Available</p>
<p v-else-if="email && !validEmail && !emailError" id="f_email_help" class="text-xs text-danger font-weight-bold mt-1 mb-0">Email already in use</p>
<p v-else-if="email && emailError" id="f_email_help" class="text-xs text-danger font-weight-bold mt-1 mb-0">{{ emailError }}</p>
<p v-else id="f_email_help" class="text-xs text-muted mt-1 mb-0">We'll never share your email with anyone else.</p>
</div>
</div>
<div v-if="email && email.length && validEmail" class="pt-3">
<div class="form-group has-float-label">
<input type="password" class="form-control" id="f_password" aria-describedby="f_password_help" autocomplete="new-password" v-model="password" autofocus="autofocus" />
<label for="f_password">Password</label>
<div id="f_password_help" class="text-xs text-muted">Use a memorable password that you don't use on other sites.</div>
</div>
</div>
<div v-if="password && password.length >= 8" class="pt-3">
<div class="form-group has-float-label">
<input type="password" class="form-control" id="f_passwordConfirm" aria-describedby="f_passwordConfirm_help" autocomplete="new-password" v-model="passwordConfirm" autofocus="autofocus" />
<label for="f_passwordConfirm">Confirm Password</label>
<div id="f_passwordConfirm_help" class="text-xs text-muted">Re-enter your password.</div>
</div>
</div>
</div>
</template>
<template v-else-if="step === 6">
<div class="wrapper-mh">
<div class="my-5">
<p class="lead text-center font-weight-bold mb-0">You're almost ready!</p>
<p class="text-center text-lighter text-xs">Confirm your email and other info</p>
</div>
<div class="card shadow-none border" style="border-radius: 1rem;">
<div class="card-body">
<div class="d-flex gap-1">
<img :src="initialData.avatar" width="90" height="90" class="rounded-circle">
<div>
<p class="lead font-weight-bold mb-n1">@{{username}}</p>
<p class="small font-weight-light text-muted mb-1">{{username}}@pixelfed.test</p>
<p class="text-xs mb-0 text-lighter">{{ form.bio.slice(0, 80) + '...' }}</p>
</div>
</div>
</div>
</div>
<div class="list-group mt-3" style="border-radius: 1rem;">
<div class="list-group-item d-flex align-items-center justify-content-between">
<div class="text-xs">Email</div>
<div class="font-weight-bold">{{ email }}</div>
</div>
<div class="list-group-item d-flex align-items-center justify-content-between">
<div class="text-xs">Following Imports</div>
<div class="font-weight-bold">{{ selectedFollowing ? selectedFollowing.length : 0 }}</div>
</div>
</div>
</div>
</template>
<template v-else-if="step === 7">
<div class="wrapper-mh">
<div class="w-100 d-flex flex-column gap-1">
<b-progress :value="submitProgress" :max="100" height="1rem" animated></b-progress>
<p class="text-center text-xs text-lighter">{{ submitMessage }}</p>
</div>
</div>
</template>
<hr>
<template v-if="step === 7">
<div class="d-flex align-items-center justify-content-center gap-1 mb-2">
<button class="btn btn-outline-primary font-weight-bold btn-block my-0" @click="handleBack()">Back</button>
<button class="btn btn-primary font-weight-bold btn-block my-0" @click="handleJoin()" disabled>Continue</button>
</div>
</template>
<template v-else>
<div class="d-flex align-items-center justify-content-center gap-1 mb-2">
<button v-if="step > 1" class="btn btn-outline-primary font-weight-bold btn-block my-0" :disabled="isSubmitting" @click="handleBack()">Back</button>
<button
v-if="step === 6"
class="btn btn-primary font-weight-bold btn-block my-0"
:disabled="isSubmitting"
@click="handleJoin()">
<b-spinner v-if="isSubmitting" small />
<span v-else>Continue</span>
</button>
<button v-else class="btn btn-primary font-weight-bold btn-block my-0" :disabled="canProceed()" @click="handleProceed()">Next</button>
</div>
<template v-if="isSubmitting ? false : step <= 6">
<hr>
<p class="text-center mb-0">
<a class="font-weight-bold" href="/login">Go back to login</a>
</p>
</template>
</template>
</div>
</template>
<script type="text/javascript">
import {debounce} from './../../../js/util/debounce.js';
import { InstagramLoader } from 'vue-content-loader';
export default {
props: {
initialData: {
type: Object
}
},
components: {
InstagramLoader,
},
data() {
return {
step: 1,
validUsername: false,
usernameError: undefined,
username: this.initialData.username,
email: undefined,
emailError: undefined,
validEmail: false,
password: undefined,
passwordConfirm: undefined,
passwordValid: false,
following: [],
followingFetched: false,
selectedFollowing: [],
form: {
importAvatar: true,
bio: this.stripTagsPreserveNewlines(this.initialData.note),
display_name: this.initialData.display_name,
},
isSubmitting: false,
submitProgress: 0,
submitMessage: 'Please wait...',
isImportingFollowing: false,
accountToId: [],
followingIds: [],
accessToken: undefined,
}
},
mounted() {
this.checkUsernameAvailability();
},
watch: {
username: debounce(function(username) {
this.checkUsernameAvailability();
}, 500),
email: debounce(function(email) {
this.checkEmailAvailability();
}, 500),
passwordConfirm: function(confirm) {
this.checkPasswordConfirm(confirm);
},
selectedFollowing: function(account) {
this.lookupSelected(account);
}
},
methods: {
checkPasswordConfirm(password) {
if(!this.password || !password) {
return;
}
this.passwordValid = password.trim() === this.password.trim();
},
handleBack() {
event.currentTarget.blur();
this.step--;
},
handleProceed() {
event.currentTarget.blur();
this.step++;
if(!this.followingFetched) {
this.fetchFollowing();
}
},
checkUsernameAvailability() {
axios.post('/auth/raw/mastodon/s/username-check', {
username: this.username
})
.then(res => {
if(res.data && res.data.hasOwnProperty('exists')) {
this.usernameError = undefined;
this.validUsername = res.data.exists == false;
}
})
.catch(err => {
this.usernameError = err.response.data.message;
})
},
checkEmailAvailability() {
axios.post('/auth/raw/mastodon/s/email-check', {
email: this.email
})
.then(res => {
if(!res.data) {
this.emailError = undefined;
this.validEmail = false;
return;
}
if(res.data && res.data.hasOwnProperty('banned') && res.data.banned) {
this.emailError = 'This email provider is not supported, please use a different email address.';
this.validEmail = false;
return;
}
if(res.data && res.data.hasOwnProperty('exists')) {
this.emailError = undefined;
this.validEmail = res.data.exists == false;
}
})
.catch(err => {
this.emailError = err.response.data.message;
})
},
canProceed() {
switch(this.step) {
case 1:
return false;
break;
case 2:
return (this.usernameError || !this.validUsername);
break;
case 3:
return false;
break;
case 4:
return false;
break;
case 5:
return (
!this.email ||
!this.validEmail ||
!this.password ||
!this.password.length ||
this.password.length < 8 ||
!this.passwordConfirm ||
!this.passwordConfirm.length ||
this.passwordConfirm.length < 8 ||
!this.passwordValid
);
break;
case 6:
break;
}
},
handleFollower(event, account) {
let state = event.target.checked;
if(state) {
if(this.selectedFollowing.indexOf(account.url) == -1) {
this.selectedFollowing.push(account.url)
}
} else {
this.selectedFollowing = this.selectedFollowing.filter(s => s !== account.url);
}
},
handleFollowerSelectAll() {
this.selectedFollowing = this.following.map(f => f.url);
},
handleFollowerUnselectAll() {
this.selectedFollowing = [];
},
lookupSelected(accounts) {
if(!accounts || !accounts.length) {
return;
}
for (var i = accounts.length - 1; i >= 0; i--) {
let acct = accounts[i];
if(!this.accountToId.map(a => a.url).includes(acct)) {
axios.post('/auth/raw/mastodon/s/account-to-id', {
account: acct
})
.then(res => {
this.accountToId.push({
id: res.data.id,
url: acct
})
})
}
}
},
fetchFollowing() {
axios.post('/auth/raw/mastodon/s/following')
.then(res => {
this.following = res.data.following;
this.followingFetched = true;
})
.finally(() => {
setTimeout(() => {
this.followingFetched = true;
}, 1000)
})
},
stripTagsPreserveNewlines(htmlString) {
const parser = new DOMParser();
const document = parser.parseFromString(htmlString, 'text/html');
const body = document.body;
let strippedString = '';
function traverse(element) {
const nodeName = element.nodeName.toLowerCase();
if (nodeName === 'p') {
strippedString += '\n';
} else if (nodeName === '#text') {
strippedString += element.textContent;
}
const childNodes = element.childNodes;
for (let i = 0; i < childNodes.length; i++) {
traverse(childNodes[i]);
}
}
traverse(body);
strippedString = strippedString.trim();
return strippedString;
},
handleJoin() {
this.isSubmitting = true;
this.step = 7;
this.submitProgress = 10;
axios.post('/auth/raw/mastodon/s/submit', {
email: this.email,
name: this.form.display_name,
password: this.password,
password_confirmation: this.passwordConfirm,
username: this.username,
})
.then(res => {
if(res.data.hasOwnProperty('token') && res.data.token) {
this.accessToken = res.data.token;
setTimeout(() => {
this.submitProgress = 20;
this.submitMessage = 'Claiming your username...';
this.storeBio();
}, 2000);
} else {
swal('Something went wrong', 'An unexpected error occured, please try again later');
}
})
},
storeBio() {
axios.post('/auth/raw/mastodon/s/store-bio', {
bio: this.form.bio
})
.then(res => {
this.submitProgress = 30;
this.submitMessage = 'Importing your bio...';
})
.finally(() => {
this.storeFollowing();
})
},
storeFollowing() {
this.submitProgress = 40;
this.submitMessage = 'Importing following accounts...';
if(!this.selectedFollowing || !this.selectedFollowing.length) {
setTimeout(() => {
this.iterateFollowing();
}, 500);
return;
}
let ids = this.selectedFollowing
.map(id => {
return this.accountToId.filter(ai => ai.url == id).map(ai => ai.id);
})
.flat()
.filter(r => r && r.length && typeof r === 'string')
this.followingIds = ids;
setTimeout(() => {
this.iterateFollowing();
}, 500);
// axios.post('/auth/raw/mastodon/s/store-following', {
// accounts: this.selectedFollowing
// })
// .then(res => {
// this.followingIds = res.data;
// this.submitProgress = 40;
// this.submitMessage = 'Importing following accounts...';
// setTimeout(() => {
// this.iterateFollowing();
// }, 1000);
// })
},
iterateFollowing() {
if(!this.followingIds || !this.followingIds.length) {
this.storeAvatar();
return;
}
let id = this.followingIds.pop();
return this.handleFollow(id);
},
handleFollow(id) {
const config = {
headers: { Authorization: `Bearer ${this.accessToken}` }
};
axios.post(`/api/v1/accounts/${id}/follow`, {}, config)
.then(res => {
})
.finally(() => {
this.iterateFollowing();
})
},
storeAvatar() {
this.submitProgress = 70;
this.submitMessage = 'Importing your avatar...';
if(this.form.importAvatar == false) {
this.submitProgress = 90;
this.submitMessage = 'Preparing your account...';
this.finishUp();
return;
}
axios.post('/auth/raw/mastodon/s/store-avatar', {
avatar_url: this.initialData.avatar
})
.then(res => {
this.submitProgress = 90;
this.submitMessage = 'Preparing your account...';
this.finishUp();
})
},
finishUp() {
this.submitProgress = 92;
this.submitMessage = 'Finishing up...';
axios.post('/auth/raw/mastodon/s/finish-up')
.then(() => {
this.$emit('setCanReload');
this.submitProgress = 95;
this.submitMessage = 'Logging you in...';
setTimeout(() => {
this.submitProgress = 100;
window.location.reload();
}, 5000)
})
}
}
}
</script>
<style lang="scss">
.wrapper-mh {
min-height: 429px;
display: flex;
justify-content: center;
flex-direction: column;
}
.limit-h {
height: 300px;
overflow-x: hidden;
overflow-y: auto;
}
.has-float-label {
display: block;
position: relative;
}
.has-float-label label, .has-float-label > span {
position: absolute;
left: 0;
top: 0;
cursor: text;
font-size: 75%;
font-weight: bold;
opacity: 1;
-webkit-transition: all .2s;
transition: all .2s;
top: -.5em;
left: 0.75rem;
z-index: 3;
line-height: 1;
padding: 0 4px;
background: #fff;
}
.has-float-label label::after, .has-float-label > span::after {
content: " ";
display: block;
position: absolute;
background: #fff;
height: 2px;
top: 50%;
left: -.2em;
right: -.2em;
z-index: -1;
}
.has-float-label .form-control::-webkit-input-placeholder {
opacity: 1;
-webkit-transition: all .2s;
transition: all .2s;
}
.has-float-label .form-control::-moz-placeholder {
opacity: 1;
transition: all .2s;
}
.has-float-label .form-control:-ms-input-placeholder {
opacity: 1;
transition: all .2s;
}
.has-float-label .form-control::placeholder {
opacity: 1;
-webkit-transition: all .2s;
transition: all .2s;
}
.has-float-label .form-control:placeholder-shown:not(:focus)::-webkit-input-placeholder {
opacity: 0;
}
.has-float-label .form-control:placeholder-shown:not(:focus)::-moz-placeholder {
opacity: 0;
}
.has-float-label .form-control:placeholder-shown:not(:focus):-ms-input-placeholder {
opacity: 0;
}
.has-float-label .form-control:placeholder-shown:not(:focus)::placeholder {
opacity: 0;
}
.has-float-label .form-control:placeholder-shown:not(:focus) + * {
font-size: 150%;
opacity: .5;
top: .3em;
}
.input-group .has-float-label {
-webkit-box-flex: 1;
-webkit-flex-grow: 1;
-ms-flex-positive: 1;
flex-grow: 1;
margin-bottom: 0;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-pack: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
}
.input-group .has-float-label .form-control {
width: 100%;
border-radius: 0.25rem;
}
.input-group .has-float-label:not(:last-child), .input-group .has-float-label:not(:last-child) .form-control {
border-bottom-right-radius: 0;
border-top-right-radius: 0;
border-right: 0;
}
.input-group .has-float-label:not(:first-child), .input-group .has-float-label:not(:first-child) .form-control {
border-bottom-left-radius: 0;
border-top-left-radius: 0;
}
.opacity-0 {
opacity: 0;
transition: opacity 0.5s;
}
.sl {
.progress {
background-color: #fff;
}
#tick {
stroke: #63bc01;
stroke-width: 6;
transition: all 1s;
}
#circle {
stroke: #63bc01;
stroke-width: 6;
transform-origin: 50px 50px 0;
transition: all 1s;
}
.progress #tick {
opacity: 0;
}
.ready #tick {
stroke-dasharray: 1000;
stroke-dashoffset: 1000;
animation: draw 8s ease-out forwards;
}
.progress #circle {
stroke: #4c4c4c;
stroke-dasharray: 314;
stroke-dashoffset: 1000;
animation: spin 3s linear infinite;
}
.ready #circle {
stroke-dashoffset: 66;
stroke: #63bc01;
}
#circle {
stroke-dasharray: 500;
}
@keyframes spin {
0% {
transform: rotate(0deg);
stroke-dashoffset: 66;
}
50% {
transform: rotate(540deg);
stroke-dashoffset: 314;
}
100% {
transform: rotate(1080deg);
stroke-dashoffset: 66;
}
}
@keyframes draw {
to {
stroke-dashoffset: 0;
}
}
#scheck {
width: 300px;
height: 300px;
}
}
</style>

Wyświetl plik

@ -178,9 +178,13 @@
</span>
<span v-else>
<a v-if="!pageLoading && (page > 1 && page <= 2) || (page == 1 && ids.length != 0) || page == 'cropPhoto'" class="font-weight-bold text-decoration-none" href="#" @click.prevent="nextPage">Next</a>
<a v-if="!pageLoading && page == 3" class="font-weight-bold text-decoration-none" href="#" @click.prevent="compose()">Post</a>
<template v-if="!pageLoading && page == 3" >
<b-spinner v-if="isPosting" small />
<a v-else class="font-weight-bold text-decoration-none" href="#" @click.prevent="compose()">Post</a>
</template>
<a v-if="!pageLoading && page == 'addText'" class="font-weight-bold text-decoration-none" href="#" @click.prevent="composeTextPost()">Post</a>
<a v-if="!pageLoading && page == 'video-2'" class="font-weight-bold text-decoration-none" href="#" @click.prevent="compose()">Post</a>
<a v-if="!pageLoading && page == 'video-2'" class="font-weight-bold text-decoration-none" href="#" @click.prevent="compose()">Post</a>
<span v-if="!pageLoading && page == 'filteringMedia'" class="font-weight-bold text-decoration-none text-muted">Next</span>
</span>
</div>
</div>
@ -201,10 +205,10 @@
</div>
</div>
<div v-if="page == 'textOptions'" class="w-100 h-100" style="min-height: 280px;">
<div v-else-if="page == 'textOptions'" class="w-100 h-100" style="min-height: 280px;">
</div>
<div v-if="page == 'addText'" class="w-100 h-100" style="min-height: 280px;">
<div v-else-if="page == 'addText'" class="w-100 h-100" style="min-height: 280px;">
<div class="mt-2">
<div class="media px-3">
<div class="media-body">
@ -236,7 +240,7 @@
</div>
</div>
<div v-if="page == 1" class="w-100 h-100 d-flex justify-content-center align-items-center" style="min-height: 400px;">
<div v-else-if="page == 1" class="w-100 h-100 d-flex justify-content-center align-items-center" style="min-height: 400px;">
<div class="text-center">
<div v-if="media.length == 0" class="card my-md-3 shadow-none border compose-action text-decoration-none text-dark">
<div @click.prevent="addMedia" class="card-body py-2">
@ -337,7 +341,7 @@
</div>
</div>
<div v-if="page == 'cropPhoto'" class="w-100 h-100">
<div v-else-if="page == 'cropPhoto'" class="w-100 h-100">
<div v-if="ids.length > 0">
<vue-cropper
ref="cropper"
@ -352,7 +356,7 @@
</div>
</div>
<div v-if="page == 2" class="w-100 h-100">
<div v-else-if="page == 2" class="w-100 h-100">
<div v-if="media.length == 1">
<div slot="img" style="display:flex;min-height: 420px;align-items: center;">
<img :class="'d-block img-fluid w-100 ' + [media[carouselCursor].filter_class?media[carouselCursor].filter_class:'']" :src="media[carouselCursor].url" :alt="media[carouselCursor].description" :title="media[carouselCursor].description">
@ -368,7 +372,9 @@
</li>
<li class="nav-item" v-for="(filter, index) in filters">
<div class="p-1 pt-3">
<img :src="media[carouselCursor].url" width="100px" height="60px" :class="filter[1]" v-on:click.prevent="toggleFilter($event, filter[1])">
<div class="rounded" :class="filter[1]">
<img :src="media[carouselCursor].url" width="100px" height="60px" v-on:click.prevent="toggleFilter($event, filter[1])">
</div>
</div>
<a :class="[media[carouselCursor].filter_class == filter[1] ? 'nav-link text-primary active' : 'nav-link text-muted']" href="#" v-on:click.prevent="toggleFilter($event, filter[1])">{{filter[0]}}</a>
</li>
@ -376,20 +382,21 @@
</div>
</div>
<div v-else-if="media.length > 1" class="d-flex-inline px-2 pt-2">
<ul class="nav media-drawer-filters text-center">
<ul class="nav media-drawer-filters text-center pb-3">
<li class="nav-item mx-md-4">&nbsp;</li>
<li v-for="(m, i) in media" class="nav-item mx-md-4">
<li v-for="(m, i) in media" :key="m.id + ':' + carouselCursor" class="nav-item mx-md-4">
<div class="nav-link" style="display:block;width:300px;height:300px;" @click="carouselCursor = i">
<!-- <img :class="'d-block img-fluid w-100 ' + [m.filter_class?m.filter_class:'']" :src="m.url" :alt="m.description" :title="m.description"> -->
<span :class="[m.filter_class?m.filter_class:'']">
<span :class="'rounded border ' + [i == carouselCursor ? ' border-primary shadow':'']" :style="'display:block;padding:5px;width:100%;height:100%;background-image: url(' + m.url + ');background-size:cover;border-width:3px !important;'"></span>
</span>
<div :class="[m.filter_class?m.filter_class:'']" style="width:100%;height:100%;display:block;">
<div :class="'rounded ' + [i == carouselCursor ? ' border border-primary shadow':'']" :style="'display:block;width:100%;height:100%;background-image: url(' + m.url + ');background-size:cover;'"></div>
</div>
</div>
<div v-if="i == carouselCursor" class="text-center mb-0 small text-lighter font-weight-bold pt-2">
<button class="btn btn-link" @click="mediaReorder('prev')"><i class="far fa-chevron-circle-left"></i></button>
<span class="cursor-pointer" @click.prevent="showCropPhotoCard">Crop</span>
<span class="cursor-pointer px-3" @click.prevent="showEditMediaCard()">Edit</span>
<span class="cursor-pointer" @click="deleteMedia()">Delete</span>
<button class="btn btn-link" @click="mediaReorder('next')"><i class="far fa-chevron-circle-right"></i></button>
</div>
</li>
<li class="nav-item mx-md-4">&nbsp;</li>
@ -417,7 +424,7 @@
</div>
</div>
<div v-if="page == 3" class="w-100 h-100">
<div v-else-if="page == 3" class="w-100 h-100">
<div class="border-bottom mt-2">
<div class="media px-3">
<img :src="media[0].url" width="42px" height="42px" :class="[media[0].filter_class?'mr-2 ' + media[0].filter_class:'mr-2']">
@ -524,7 +531,7 @@
</div>
</div>
<div v-if="page == 'tagPeople'" class="w-100 h-100 p-3">
<div v-else-if="page == 'tagPeople'" class="w-100 h-100 p-3">
<autocomplete
v-show="taggedUsernames.length < 10"
:search="tagSearch"
@ -557,14 +564,14 @@
<p class="font-weight-bold text-center small text-muted pt-3 mb-0">When you tag someone, they are sent a notification.<br>For more information on tagging, <a href="#" class="text-primary" @click.prevent="showTagHelpCard()">click here</a>.</p>
</div>
<div v-if="page == 'tagPeopleHelp'" class="w-100 h-100 p-3">
<div v-else-if="page == 'tagPeopleHelp'" class="w-100 h-100 p-3">
<p class="mb-0 text-center py-3 px-2 lead">Tagging someone is like mentioning them, with the option to make it private between you.</p>
<p class="mb-3 py-3 px-2 font-weight-lighter">
You can choose to tag someone in public or private mode. Public mode will allow others to see who you tagged in the post and private mode tagged users will not be shown to others.
</p>
</div>
<div v-if="page == 'addLocation'" class="w-100 h-100 p-3">
<div v-else-if="page == 'addLocation'" class="w-100 h-100 p-3">
<p class="mb-0">Add Location</p>
<autocomplete
:search="locationSearch"
@ -576,7 +583,7 @@
</autocomplete>
</div>
<div v-if="page == 'advancedSettings'" class="w-100 h-100">
<div v-else-if="page == 'advancedSettings'" class="w-100 h-100">
<div class="list-group list-group-flush">
<!-- <div class="d-none list-group-item d-flex justify-content-between">
<div>
@ -650,7 +657,7 @@
</div>
</div>
<div v-if="page == 'visibility'" class="w-100 h-100">
<div v-else-if="page == 'visibility'" class="w-100 h-100">
<div class="list-group list-group-flush">
<div
v-if="!profile.locked"
@ -675,7 +682,7 @@
</div>
</div>
<div v-if="page == 'altText'" class="w-100 h-100 p-3">
<div v-else-if="page == 'altText'" class="w-100 h-100 p-3">
<div v-for="(m, index) in media">
<div class="media">
<img :src="m.preview_url" class="mr-3" width="50px" height="50px">
@ -692,7 +699,7 @@
</p>
</div>
<div v-if="page == 'addToCollection'" class="w-100 h-100 p-3">
<div v-else-if="page == 'addToCollection'" class="w-100 h-100 p-3">
<div v-if="collectionsLoaded && collections.length" class="list-group mb-3 collections-list-group">
<div
v-for="(collection, index) in collections"
@ -721,19 +728,19 @@
</p>
</div>
<div v-if="page == 'schedulePost'" class="w-100 h-100 p-3">
<div v-else-if="page == 'schedulePost'" class="w-100 h-100 p-3">
<p class="text-center lead text-muted mb-0 py-5">This feature is not available yet.</p>
</div>
<div v-if="page == 'mediaMetadata'" class="w-100 h-100 p-3">
<div v-else-if="page == 'mediaMetadata'" class="w-100 h-100 p-3">
<p class="text-center lead text-muted mb-0 py-5">This feature is not available yet.</p>
</div>
<div v-if="page == 'addToStory'" class="w-100 h-100 p-3">
<div v-else-if="page == 'addToStory'" class="w-100 h-100 p-3">
<p class="text-center lead text-muted mb-0 py-5">This feature is not available yet.</p>
</div>
<div v-if="page == 'editMedia'" class="w-100 h-100 p-3">
<div v-else-if="page == 'editMedia'" class="w-100 h-100 p-3">
<div class="media">
<img :src="media[carouselCursor].preview_url" class="mr-3" width="50px" height="50px">
<div class="media-body">
@ -770,7 +777,7 @@
</p>
</div>
<div v-if="page == 'video-2'" class="w-100 h-100">
<div v-else-if="page == 'video-2'" class="w-100 h-100">
<div v-if="video.title.length" class="border-bottom">
<div class="media p-3">
<img :src="media[0].url" width="100px" height="70px" :class="[media[0].filter_class?'mr-2 ' + media[0].filter_class:'mr-2']">
@ -833,6 +840,12 @@
</div>
</div>
<div v-else-if="page == 'filteringMedia'" class="w-100 h-100 py-5">
<div class="d-flex flex-column align-items-center justify-content-center py-5">
<b-spinner small />
<p class="font-weight-bold mt-3">Applying filters...</p>
</div>
</div>
</div>
<!-- card-footers -->
@ -910,6 +923,7 @@ export default {
},
namedPages: [
'filteringMedia',
'cropPhoto',
'tagPeople',
'addLocation',
@ -943,7 +957,6 @@ export default {
cb(res.data);
})
.catch(err => {
console.log(err);
})
})
},
@ -957,7 +970,6 @@ export default {
cb(res.data);
})
.catch(err => {
console.log(err);
})
})
}
@ -1032,6 +1044,10 @@ export default {
collectionsPage: 1,
collectionsCanLoadMore: false,
spoilerText: undefined,
isFilteringMedia: false,
filteringMediaTimeout: undefined,
filteringRemainingCount: 0,
isPosting: false,
}
},
@ -1242,6 +1258,50 @@ export default {
});
},
mediaReorder(dir) {
const m = this.media;
const cur = this.carouselCursor;
const pla = m[cur];
let res = [];
let cursor = 0;
if(dir == 'prev') {
if(cur == 0) {
for (let i = cursor; i < m.length - 1; i++) {
res[i] = m[i+1];
}
res[m.length - 1] = pla;
cursor = 0;
} else {
res = this.handleSwap(m, cur, cur - 1);
cursor = cur - 1;
}
} else {
if(cur == m.length - 1) {
res = m;
let lastItem = res.pop();
res.unshift(lastItem);
cursor = m.length - 1;
} else {
res = this.handleSwap(m, cur, cur + 1);
cursor = cur + 1;
}
}
this.$nextTick(() => {
this.media = res;
this.carouselCursor = cursor;
})
},
handleSwap(arr, index1, index2) {
if (index1 >= 0 && index1 < arr.length && index2 >= 0 && index2 < arr.length) {
const temp = arr[index1];
arr[index1] = arr[index2];
arr[index2] = temp;
return arr;
}
},
compose() {
let state = this.composeState;
@ -1254,8 +1314,15 @@ export default {
return;
}
switch(state) {
case 'publish' :
case 'publish':
this.isPosting = true;
let count = this.media.filter(m => m.filter_class && !m.hasOwnProperty('is_filtered')).length;
if(count) {
this.applyFilterToMedia();
return;
}
if(this.composeSettings.media_descriptions === true) {
let count = this.media.filter(m => {
return !m.hasOwnProperty('alt') || m.alt.length < 2;
@ -1377,6 +1444,10 @@ export default {
switch(this.mode) {
case 'photo':
switch(this.page) {
case 'filteringMedia':
this.page = 2;
break;
case 'addText':
this.page = 1;
break;
@ -1411,6 +1482,10 @@ export default {
case 'video':
switch(this.page) {
case 'filteringMedia':
this.page = 2;
break;
case 'licensePicker':
this.page = 'video-2';
break;
@ -1431,6 +1506,10 @@ export default {
this.page = 1;
break;
case 'filteringMedia':
this.page = 2;
break;
case 'textOptions':
this.page = 'addText';
break;
@ -1470,6 +1549,9 @@ export default {
this.page = 2;
break;
case 'filteringMedia':
break;
case 'cropPhoto':
this.pageLoading = true;
let self = this;
@ -1495,14 +1577,7 @@ export default {
break;
case 2:
if(this.currentFilter) {
if(window.confirm('Are you sure you want to apply this filter?')) {
this.applyFilterToMedia();
this.page++;
}
} else {
this.page++;
}
break;
case 3:
this.page++;
@ -1649,43 +1724,73 @@ export default {
// this is where the magic happens
var ua = navigator.userAgent.toLowerCase();
if(ua.indexOf('firefox') == -1 && ua.indexOf('chrome') == -1) {
this.isPosting = false;
swal('Oops!', 'Your browser does not support the filter feature.', 'error');
this.page = 3;
return;
}
let medias = this.media;
let media = null;
const canvas = document.getElementById('pr_canvas');
const ctx = canvas.getContext('2d');
let image = document.getElementById('pr_img');
let blob = null;
let data = null;
for (var i = medias.length - 1; i >= 0; i--) {
media = medias[i];
if(media.filter_class) {
image.src = media.url;
image.addEventListener('load', e => {
canvas.width = image.width;
canvas.height = image.height;
ctx.filter = App.util.filterCss[media.filter_class];
ctx.drawImage(image, 0, 0, image.width, image.height);
ctx.save();
canvas.toBlob(function(blob) {
data = new FormData();
data.append('file', blob);
data.append('id', media.id);
axios.post('/api/compose/v0/media/update', data).then(res => {
}).catch(err => {
});
});
}, media.mime, 0.9);
ctx.clearRect(0, 0, image.width, image.height);
}
}
let count = this.media.filter(m => m.filter_class).length;
if(count) {
this.page = 'filteringMedia';
this.filteringRemainingCount = count;
this.$nextTick(() => {
this.isFilteringMedia = true;
this.media.forEach((media, idx) => this.applyFilterToMediaSave(media, idx));
})
} else {
this.page = 3;
}
},
applyFilterToMediaSave(media, idx) {
if(!media.filter_class) {
return;
}
let self = this;
let data = null;
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
let image = document.createElement('img');
image.src = media.url;
image.addEventListener('load', e => {
canvas.width = image.width;
canvas.height = image.height;
ctx.filter = App.util.filterCss[media.filter_class];
ctx.drawImage(image, 0, 0, image.width, image.height);
ctx.save();
canvas.toBlob(function(blob) {
data = new FormData();
data.append('file', blob);
data.append('id', media.id);
axios.post('/api/compose/v0/media/update', data)
.then(res => {
self.media[idx].is_filtered = true;
self.updateFilteringMedia();
}).catch(err => {
});
});
}, media.mime, 0.9);
ctx.clearRect(0, 0, image.width, image.height);
},
updateFilteringMedia() {
this.filteringRemainingCount--;
this.filteringMediaTimeout = setTimeout(() => this.filteringMediaTimeoutJob(), 500);
},
filteringMediaTimeoutJob() {
if(this.filteringRemainingCount === 0) {
this.isFilteringMedia = false;
clearTimeout(this.filteringMediaTimeout);
setTimeout(() => this.compose(), 500);
} else {
clearTimeout(this.filteringMediaTimeout);
this.filteringMediaTimeout = setTimeout(() => this.filteringMediaTimeoutJob(), 1000);
}
},
tagSearch(input) {
if (input.length < 1) { return []; }
let self = this;
@ -1800,7 +1905,6 @@ export default {
}
window.location.href = res.data.url;
}).catch(err => {
console.log(err.response.data.error);
if(err.response.data.hasOwnProperty('error')) {
if(err.response.data.error == 'Duplicate detected.') {
this.postingPoll = false;

Wyświetl plik

@ -0,0 +1,11 @@
export function debounce (fn, delay) {
var timeoutID = null
return function () {
clearTimeout(timeoutID)
var args = arguments
var that = this
timeoutID = setTimeout(function () {
fn.apply(that, args)
}, delay)
}
}