1
0
Fork 0

Compare commits

...

41 Commits

Author SHA1 Message Date
daniel ae60c99679
Merge pull request #5052 from pixelfed/staging
Update profile embed, fix height bug
2024-04-20 05:59:25 -06:00
Daniel Supernault a54b4fb038
Update profile embed, fix height bug 2024-04-20 05:59:01 -06:00
daniel 2f7481205c
Merge pull request #5051 from pixelfed/staging
Staging
2024-04-20 05:03:29 -06:00
Daniel Supernault cde17f5af7
Update changelog 2024-04-20 05:03:10 -06:00
Daniel Supernault 433bc4c286
Update embed.js 2024-04-20 05:02:58 -06:00
daniel 5d407ededf
Merge pull request #5050 from pixelfed/staging
Update profile embed view, fix height bug
2024-04-20 05:01:50 -06:00
Daniel Supernault 65166570c5
Update profile embed view, fix height bug 2024-04-20 05:01:04 -06:00
daniel 610326e7b0
Merge pull request #5049 from pixelfed/staging
Refactor embeds
2024-04-20 04:36:08 -06:00
Daniel Supernault 6fc066a213
Update changelog 2024-04-20 04:35:10 -06:00
Daniel Supernault 8b8b1ffc5c
Update ProfileController, refactor profile embeds 2024-04-20 04:33:47 -06:00
Daniel Supernault 9a7acc12a6
Update StatusController, refactor status embeds 2024-04-20 04:26:47 -06:00
Daniel Supernault 51b6fe7dc8
Refactor embeds 2024-04-20 04:25:22 -06:00
daniel c4ffa62242
Merge pull request #5048 from pixelfed/staging
Update webpack config
2024-04-20 02:01:19 -06:00
Daniel Supernault 87ee0633fe
Update assets, move presenters 2024-04-20 01:26:51 -06:00
Daniel Supernault ded660b2c4
Update webpack config 2024-04-20 00:55:21 -06:00
daniel 4d04227d41
Merge pull request #5043 from pixelfed/staging
Staging
2024-04-12 04:44:12 -06:00
Daniel Supernault 26f92c93ce
Update compiled assets 2024-04-12 04:43:38 -06:00
Daniel Supernault 81566987e4
Update changelog 2024-04-12 04:43:21 -06:00
Daniel Supernault 8af2360779
Update VideoPlayer component, add playsinline attribute to video element 2024-04-12 04:42:57 -06:00
daniel b3fb69c5b1
Merge pull request #5042 from pixelfed/staging
Staging
2024-04-12 04:03:20 -06:00
Daniel Supernault f30f7d79fb
Update changelog 2024-04-12 04:00:46 -06:00
Daniel Supernault 2deb65d874
Update compiled assets 2024-04-12 04:00:25 -06:00
Daniel Supernault ad03291699
Update VideoPresenter component, add webkit-playsinline attribute to video element to prevent the full screen video player 2024-04-12 03:56:33 -06:00
daniel 6be21891d5
Merge pull request #5041 from pixelfed/staging
Staging
2024-04-11 20:44:15 -06:00
daniel 141f6d38a7
Merge pull request #5035 from jippi/jippi-fork
Docker fixes
2024-04-11 20:43:52 -06:00
Daniel Supernault 4608c66c0b
Re-add .env.example 2024-04-11 20:43:24 -06:00
Christian Winther e227ee1bd5 use DOCKER_DB_HOST_PORT when checking if database is ready or not 2024-04-06 10:53:48 +00:00
Christian Winther dbc5df849f use ENABLE_CONFIG_CACHE when dumping composer autoload 2024-04-06 10:06:07 +00:00
Daniel Supernault 6bdf73de4d
Update UnfollowPipeline, fix follower count cache bug 2024-04-06 03:29:17 -06:00
daniel 5b3d0206ae
Merge pull request #5034 from pixelfed/staging
Update docker env, fix config_cache. Fixes #5033
2024-04-06 03:20:31 -06:00
Daniel Supernault 858fcbf606
Update docker env, fix config_cache. Fixes #5033 2024-04-06 03:19:50 -06:00
daniel 57df06a0b6
Merge pull request #5032 from pixelfed/staging
Staging
2024-04-06 02:56:48 -06:00
Daniel Supernault db1a4c9f8e
Update changelog 2024-04-06 02:48:31 -06:00
Daniel Supernault ce4beab9c8
Update composer deps 2024-04-06 02:48:03 -06:00
Daniel Supernault 9d5479de39
Update compiled assets 2024-04-06 02:47:39 -06:00
Daniel Supernault 512518d319
Update npm deps 2024-04-06 02:47:19 -06:00
Daniel Supernault b06a3455c2
Update compiled assets 2024-04-06 02:28:27 -06:00
Daniel Supernault 94a6e8614a
Update styles 2024-04-06 02:27:55 -06:00
Daniel Supernault 81d1e0fdab
Update context menu, add mute/block/unfollow actions and update relationship store accordingly 2024-04-06 02:27:22 -06:00
Daniel Supernault b8e96a5ff3
Update ApiV1Controller, improve refresh relations logic when (un)muting or (un)blocking 2024-04-06 01:24:09 -06:00
Daniel Supernault b7322b6874
Update PrivacySettings controller, refresh RelationshipService when unmute/unblocking 2024-04-06 01:22:52 -06:00
86 changed files with 3042 additions and 2296 deletions

View File

@ -60,6 +60,15 @@ ADMIN_DOMAIN="${APP_DOMAIN}"
# @dottie/validate required,boolean
#APP_DEBUG="false"
# Disable config cache
#
# If disabled, settings must be managed by .env variables.
#
# @default "false"
# @see https://docs.pixelfed.org/technical-documentation/config/#config_cache
# @dottie/validate required,boolean
ENABLE_CONFIG_CACHE="false"
# Enable/disable new local account registrations.
#
# @default "true"

78
.env.example Normal file
View File

@ -0,0 +1,78 @@
APP_NAME="Pixelfed"
APP_ENV="production"
APP_KEY=
APP_DEBUG="false"
# Instance Configuration
OPEN_REGISTRATION="false"
ENFORCE_EMAIL_VERIFICATION="false"
PF_MAX_USERS="1000"
OAUTH_ENABLED="true"
# Media Configuration
PF_OPTIMIZE_IMAGES="true"
IMAGE_QUALITY="80"
MAX_PHOTO_SIZE="15000"
MAX_CAPTION_LENGTH="500"
MAX_ALBUM_LENGTH="4"
# Instance URL Configuration
APP_URL="http://localhost"
APP_DOMAIN="localhost"
ADMIN_DOMAIN="localhost"
SESSION_DOMAIN="localhost"
TRUST_PROXIES="*"
# Database Configuration
DB_CONNECTION="mysql"
DB_HOST="127.0.0.1"
DB_PORT="3306"
DB_DATABASE="pixelfed"
DB_USERNAME="pixelfed"
DB_PASSWORD="pixelfed"
# Redis Configuration
REDIS_CLIENT="predis"
REDIS_SCHEME="tcp"
REDIS_HOST="127.0.0.1"
REDIS_PASSWORD="null"
REDIS_PORT="6379"
# Laravel Configuration
SESSION_DRIVER="database"
CACHE_DRIVER="redis"
QUEUE_DRIVER="redis"
BROADCAST_DRIVER="log"
LOG_CHANNEL="stack"
HORIZON_PREFIX="horizon-"
# ActivityPub Configuration
ACTIVITY_PUB="false"
AP_REMOTE_FOLLOW="false"
AP_INBOX="false"
AP_OUTBOX="false"
AP_SHAREDINBOX="false"
# Experimental Configuration
EXP_EMC="true"
## Mail Configuration (Post-Installer)
MAIL_DRIVER=log
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="pixelfed@example.com"
MAIL_FROM_NAME="Pixelfed"
## S3 Configuration (Post-Installer)
PF_ENABLE_CLOUD=false
FILESYSTEM_CLOUD=s3
#AWS_ACCESS_KEY_ID=
#AWS_SECRET_ACCESS_KEY=
#AWS_DEFAULT_REGION=
#AWS_BUCKET=<BucketName>
#AWS_URL=
#AWS_ENDPOINT=
#AWS_USE_PATH_STYLE_ENDPOINT=false

View File

@ -19,6 +19,56 @@
- Update SiteController, add curatedOnboarding method that gracefully falls back to open registration when applicable ([95199843](https://github.com/pixelfed/pixelfed/commit/95199843))
- Update AP transformers, add DeleteActor activity ([bcce1df6](https://github.com/pixelfed/pixelfed/commit/bcce1df6))
- Update commands, add user account delete cli command to federate account deletion ([4aa0e25f](https://github.com/pixelfed/pixelfed/commit/4aa0e25f))
- Update web-api popular accounts route to its own method to remove the breaking oauth scope bug ([a4bc5ce3](https://github.com/pixelfed/pixelfed/commit/a4bc5ce3))
- Update config cache ([5e4d4eff](https://github.com/pixelfed/pixelfed/commit/5e4d4eff))
- Update Config, use config_cache ([7785a2da](https://github.com/pixelfed/pixelfed/commit/7785a2da))
- Update ApiV1Dot1Controller, use config_cache for in-app registration ([b0cb4456](https://github.com/pixelfed/pixelfed/commit/b0cb4456))
- Update captcha, use config_cache helper ([8a89e3c9](https://github.com/pixelfed/pixelfed/commit/8a89e3c9))
- Update custom emoji, add config_cache support ([481314cd](https://github.com/pixelfed/pixelfed/commit/481314cd))
- Update ProfileController, fix permalink redirect bug ([75081e60](https://github.com/pixelfed/pixelfed/commit/75081e60))
- Update admin css, use font-display:swap for nucleo icons ([8a0c456e](https://github.com/pixelfed/pixelfed/commit/8a0c456e))
- Update PixelfedDirectoryController, fix boolean cast bug ([f08aab22](https://github.com/pixelfed/pixelfed/commit/f08aab22))
- Update PixelfedDirectoryController, use cached stats ([f2f2a809](https://github.com/pixelfed/pixelfed/commit/f2f2a809))
- Update AdminDirectoryController, fix type casting ([ad506e90](https://github.com/pixelfed/pixelfed/commit/ad506e90))
- Update image pipeline, use config_cache ([a72188a7](https://github.com/pixelfed/pixelfed/commit/a72188a7))
- Update cloud storage, use config_cache ([665581d8](https://github.com/pixelfed/pixelfed/commit/665581d8))
- Update pixelfed.max_album_length, use config_cache ([fecbe189](https://github.com/pixelfed/pixelfed/commit/fecbe189))
- Update media_types, use config_cache ([d670de17](https://github.com/pixelfed/pixelfed/commit/d670de17))
- Update landing settings, use config_cache ([40478f25](https://github.com/pixelfed/pixelfed/commit/40478f25))
- Update activitypub setting, use config_cache ([5071aaf4](https://github.com/pixelfed/pixelfed/commit/5071aaf4))
- Update oauth setting, use config_cache ([ce228f7f](https://github.com/pixelfed/pixelfed/commit/ce228f7f))
- Update stories config, use config_cache ([d1adb109](https://github.com/pixelfed/pixelfed/commit/d1adb109))
- Update ig import, use config_cache ([da0e0ffa](https://github.com/pixelfed/pixelfed/commit/da0e0ffa))
- Update autospam config, use config_cache ([a76cb5f4](https://github.com/pixelfed/pixelfed/commit/a76cb5f4))
- Update app.name config, use config_cache ([911446c0](https://github.com/pixelfed/pixelfed/commit/911446c0))
- Update UserObserver, fix type casting ([949e9979](https://github.com/pixelfed/pixelfed/commit/949e9979))
- Update user_filters, use config_cache ([6ce513f8](https://github.com/pixelfed/pixelfed/commit/6ce513f8))
- Update filesystems config, add to config_cache ([087b2791](https://github.com/pixelfed/pixelfed/commit/087b2791))
- Update web-admin routes, add setting api routes ([828a456f](https://github.com/pixelfed/pixelfed/commit/828a456f))
- Update hashtag component ([cee979ed](https://github.com/pixelfed/pixelfed/commit/cee979ed))
- Update AdminReadMore component, add .prevent to click action ([704e7b12](https://github.com/pixelfed/pixelfed/commit/704e7b12))
- Update admin dashboard, add admin settings partials ([eb487123](https://github.com/pixelfed/pixelfed/commit/eb487123))
- Update admin settings, refactor to vue component ([674e560f](https://github.com/pixelfed/pixelfed/commit/674e560f))
- Update ConfigCacheService, encrypt keys at rest ([3628b462](https://github.com/pixelfed/pixelfed/commit/3628b462))
- Update RemoteFollowImportRecent, use MediaPathService ([5162c070](https://github.com/pixelfed/pixelfed/commit/5162c070))
- Update AdminSettingsController, add user filter max limit settings ([ac1f0748](https://github.com/pixelfed/pixelfed/commit/ac1f0748))
- Update AdminSettingsController, add AdminSettingsService ([dcc5f416](https://github.com/pixelfed/pixelfed/commit/dcc5f416))
- Update AdminSettings component, fix user settings ([aba1e13d](https://github.com/pixelfed/pixelfed/commit/aba1e13d))
- Update AdminInstances component ([ec2fdd61](https://github.com/pixelfed/pixelfed/commit/ec2fdd61))
- Update AdminSettings, add max_account_size support ([2dcbc1d5](https://github.com/pixelfed/pixelfed/commit/2dcbc1d5))
- Update AdminSettings, use better validation for user integer settings ([d946afcc](https://github.com/pixelfed/pixelfed/commit/d946afcc))
- Update spa sass, fix timestamp dark mode bug ([4147f7c5](https://github.com/pixelfed/pixelfed/commit/4147f7c5))
- Update relationships view, fix unfollow hashtag bug. Fixes #5008 ([8c693640](https://github.com/pixelfed/pixelfed/commit/8c693640))
- Update PrivacySettings controller, refresh RelationshipService when unmute/unblocking ([b7322b68](https://github.com/pixelfed/pixelfed/commit/b7322b68))
- Update ApiV1Controller, improve refresh relations logic when (un)muting or (un)blocking ([b8e96a5f](https://github.com/pixelfed/pixelfed/commit/b8e96a5f))
- Update context menu, add mute/block/unfollow actions and update relationship store accordingly ([81d1e0fd](https://github.com/pixelfed/pixelfed/commit/81d1e0fd))
- Update docker env, fix config_cache. Fixes #5033 ([858fcbf6](https://github.com/pixelfed/pixelfed/commit/858fcbf6))
- Update UnfollowPipeline, fix follower count cache bug ([6bdf73de](https://github.com/pixelfed/pixelfed/commit/6bdf73de))
- Update VideoPresenter component, add webkit-playsinline attribute to video element to prevent the full screen video player ([ad032916](https://github.com/pixelfed/pixelfed/commit/ad032916))
- Update VideoPlayer component, add playsinline attribute to video element ([8af23607](https://github.com/pixelfed/pixelfed/commit/8af23607))
- Update StatusController, refactor status embeds ([9a7acc12](https://github.com/pixelfed/pixelfed/commit/9a7acc12))
- Update ProfileController, refactor profile embeds ([8b8b1ffc](https://github.com/pixelfed/pixelfed/commit/8b8b1ffc))
- Update profile embed view, fix height bug ([65166570](https://github.com/pixelfed/pixelfed/commit/65166570))
- ([](https://github.com/pixelfed/pixelfed/commit/))
## [v0.11.13 (2024-03-05)](https://github.com/pixelfed/pixelfed/compare/v0.11.12...v0.11.13)

View File

@ -237,7 +237,7 @@ USER ${RUNTIME_UID}:${RUNTIME_GID}
# Generate optimized autoloader now that we have all files around
RUN set -ex \
&& composer dump-autoload --optimize
&& ENABLE_CONFIG_CACHE=false composer dump-autoload --optimize
USER root

View File

@ -1200,8 +1200,8 @@ class ApiV1Controller extends Controller
if ($filter) {
$filter->delete();
UserFilterService::unblock($pid, $profile->id);
RelationshipService::refresh($pid, $id);
}
RelationshipService::refresh($pid, $id);
$resource = new Fractal\Resource\Item($profile, new RelationshipTransformer());
$res = $this->fractal->createData($resource)->toArray();
@ -2207,9 +2207,10 @@ class ApiV1Controller extends Controller
if ($filter) {
$filter->delete();
UserFilterService::unmute($pid, $profile->id);
RelationshipService::refresh($pid, $id);
}
RelationshipService::refresh($pid, $id);
$resource = new Fractal\Resource\Item($profile, new RelationshipTransformer());
$res = $this->fractal->createData($resource)->toArray();

View File

@ -172,7 +172,7 @@ class ProfileController extends Controller
$user = $this->getCachedUser($username);
abort_if(!$user, 404);
abort_if(! $user, 404);
return redirect($user->url());
}
@ -254,7 +254,7 @@ class ProfileController extends Controller
abort_if(! $profile || $profile['locked'] || ! $profile['local'], 404);
$aiCheck = Cache::remember('profile:ai-check:spam-login:'.$profile['id'], 86400, function () use ($profile) {
$aiCheck = Cache::remember('profile:ai-check:spam-login:'.$profile['id'], 3600, function () use ($profile) {
$uid = User::whereProfileId($profile['id'])->first();
if (! $uid) {
return true;
@ -348,7 +348,7 @@ class ProfileController extends Controller
return response($res)->withHeaders(['X-Frame-Options' => 'ALLOWALL']);
}
$aiCheck = Cache::remember('profile:ai-check:spam-login:'.$profile->id, 86400, function () use ($profile) {
$aiCheck = Cache::remember('profile:ai-check:spam-login:'.$profile->id, 3600, function () use ($profile) {
$exists = AccountInterstitial::whereUserId($profile->user_id)->where('is_spam', 1)->count();
if ($exists) {
return true;
@ -373,7 +373,7 @@ class ProfileController extends Controller
public function stories(Request $request, $username)
{
abort_if(!(bool) config_cache('instance.stories.enabled') || ! $request->user(), 404);
abort_if(! (bool) config_cache('instance.stories.enabled') || ! $request->user(), 404);
$profile = Profile::whereNull('domain')->whereUsername($username)->firstOrFail();
$pid = $profile->id;
$authed = Auth::user()->profile_id;

View File

@ -2,23 +2,17 @@
namespace App\Http\Controllers\Settings;
use App\AccountLog;
use App\EmailVerification;
use App\Instance;
use App\Follower;
use App\Media;
use App\Profile;
use App\User;
use App\Services\RelationshipService;
use App\UserFilter;
use App\Util\Lexer\PrettyNumber;
use App\Util\ActivityPub\Helpers;
use Auth, Cache, DB;
use Auth;
use Cache;
use DB;
use Illuminate\Http\Request;
use App\Models\UserDomainBlock;
trait PrivacySettings
{
public function privacy()
{
$user = Auth::user();
@ -35,13 +29,13 @@ trait PrivacySettings
$settings = $request->user()->settings;
$profile = $request->user()->profile;
$fields = [
'is_private',
'crawlable',
'public_dm',
'show_profile_follower_count',
'show_profile_following_count',
'indexable',
'show_atom',
'is_private',
'crawlable',
'public_dm',
'show_profile_follower_count',
'show_profile_following_count',
'indexable',
'show_atom',
];
$profile->indexable = $request->input('indexable') == 'on';
@ -67,7 +61,7 @@ trait PrivacySettings
} else {
$settings->{$field} = true;
}
} elseif ($field == 'public_dm') {
} elseif ($field == 'public_dm') {
if ($form == 'on') {
$settings->{$field} = true;
} else {
@ -85,33 +79,35 @@ trait PrivacySettings
$settings->save();
}
$pid = $profile->id;
Cache::forget('profile:settings:' . $pid);
Cache::forget('user:account:id:' . $profile->user_id);
Cache::forget('profile:follower_count:' . $pid);
Cache::forget('profile:following_count:' . $pid);
Cache::forget('profile:atom:enabled:' . $pid);
Cache::forget('profile:embed:' . $pid);
Cache::forget('pf:acct:settings:hidden-followers:' . $pid);
Cache::forget('pf:acct:settings:hidden-following:' . $pid);
Cache::forget('pf:acct-trans:hideFollowing:' . $pid);
Cache::forget('pf:acct-trans:hideFollowers:' . $pid);
Cache::forget('pfc:cached-user:wt:' . strtolower($profile->username));
Cache::forget('pfc:cached-user:wot:' . strtolower($profile->username));
Cache::forget('profile:settings:'.$pid);
Cache::forget('user:account:id:'.$profile->user_id);
Cache::forget('profile:follower_count:'.$pid);
Cache::forget('profile:following_count:'.$pid);
Cache::forget('profile:atom:enabled:'.$pid);
Cache::forget('profile:embed:'.$pid);
Cache::forget('pf:acct:settings:hidden-followers:'.$pid);
Cache::forget('pf:acct:settings:hidden-following:'.$pid);
Cache::forget('pf:acct-trans:hideFollowing:'.$pid);
Cache::forget('pf:acct-trans:hideFollowers:'.$pid);
Cache::forget('pfc:cached-user:wt:'.strtolower($profile->username));
Cache::forget('pfc:cached-user:wot:'.strtolower($profile->username));
return redirect(route('settings.privacy'))->with('status', 'Settings successfully updated!');
}
public function mutedUsers()
{
{
$pid = Auth::user()->profile->id;
$ids = (new UserFilter())->mutedUserIds($pid);
$users = Profile::whereIn('id', $ids)->simplePaginate(15);
return view('settings.privacy.muted', compact('users'));
}
public function mutedUsersUpdate(Request $request)
{
{
$this->validate($request, [
'profile_id' => 'required|integer|min:1'
'profile_id' => 'required|integer|min:1',
]);
$fid = $request->input('profile_id');
$pid = Auth::user()->profile->id;
@ -123,6 +119,8 @@ trait PrivacySettings
->firstOrFail();
$filter->delete();
});
RelationshipService::refresh($pid, $fid);
return redirect()->back();
}
@ -131,14 +129,14 @@ trait PrivacySettings
$pid = Auth::user()->profile->id;
$ids = (new UserFilter())->blockedUserIds($pid);
$users = Profile::whereIn('id', $ids)->simplePaginate(15);
return view('settings.privacy.blocked', compact('users'));
}
public function blockedUsersUpdate(Request $request)
{
{
$this->validate($request, [
'profile_id' => 'required|integer|min:1'
'profile_id' => 'required|integer|min:1',
]);
$fid = $request->input('profile_id');
$pid = Auth::user()->profile->id;
@ -150,6 +148,8 @@ trait PrivacySettings
->firstOrFail();
$filter->delete();
});
RelationshipService::refresh($pid, $fid);
return redirect()->back();
}
@ -194,7 +194,7 @@ trait PrivacySettings
$profile = Auth::user()->profile;
$settings = Auth::user()->settings;
if($mode !== 'keep-all') {
if ($mode !== 'keep-all') {
switch ($mode) {
case 'mutual-only':
$following = $profile->following()->pluck('profiles.id');
@ -209,9 +209,9 @@ trait PrivacySettings
case 'remove-all':
Follower::whereFollowingId($profile->id)->delete();
break;
default:
# code...
// code...
break;
}
}
@ -221,6 +221,7 @@ trait PrivacySettings
$settings->save();
$profile->save();
Cache::forget('profiles:private');
return [200];
}
}

View File

@ -8,6 +8,7 @@ use App\Jobs\SharePipeline\UndoSharePipeline;
use App\Jobs\StatusPipeline\RemoteStatusDelete;
use App\Jobs\StatusPipeline\StatusDelete;
use App\Profile;
use App\Services\AccountService;
use App\Services\HashidService;
use App\Services\ReblogService;
use App\Services\StatusService;
@ -113,19 +114,33 @@ class StatusController extends Controller
return response($res)->withHeaders(['X-Frame-Options' => 'ALLOWALL']);
}
$profile = Profile::whereNull(['domain', 'status'])
->whereIsPrivate(false)
->whereUsername($username)
->first();
$status = StatusService::get($id);
if (! $profile) {
if (
! $status ||
! isset($status['account'], $status['account']['id'], $status['local']) ||
! $status['local'] ||
strtolower($status['account']['username']) !== strtolower($username)
) {
$content = view('status.embed-removed');
return response($content, 404)->header('X-Frame-Options', 'ALLOWALL');
}
$profile = AccountService::get($status['account']['id'], true);
if (! $profile || $profile['locked'] || ! $profile['local']) {
$content = view('status.embed-removed');
return response($content)->header('X-Frame-Options', 'ALLOWALL');
}
$aiCheck = Cache::remember('profile:ai-check:spam-login:'.$profile->id, 86400, function () use ($profile) {
$exists = AccountInterstitial::whereUserId($profile->user_id)->where('is_spam', 1)->count();
$aiCheck = Cache::remember('profile:ai-check:spam-login:'.$profile['id'], 3600, function () use ($profile) {
$user = Profile::find($profile['id']);
if (! $user) {
return true;
}
$exists = AccountInterstitial::whereUserId($user->user_id)->where('is_spam', 1)->count();
if ($exists) {
return true;
}
@ -138,17 +153,22 @@ class StatusController extends Controller
return response($res)->withHeaders(['X-Frame-Options' => 'ALLOWALL']);
}
$status = Status::whereProfileId($profile->id)
->whereNull('uri')
->whereScope('public')
->whereIsNsfw(false)
->whereIn('type', ['photo', 'video', 'photo:album'])
->find($id);
if (! $status) {
$status = StatusService::get($id);
if (
! $status ||
! isset($status['account'], $status['account']['id']) ||
intval($status['account']['id']) !== intval($profile['id']) ||
$status['sensitive'] ||
$status['visibility'] !== 'public' ||
$status['pf_type'] !== 'photo'
) {
$content = view('status.embed-removed');
return response($content)->header('X-Frame-Options', 'ALLOWALL');
}
$showLikes = $request->filled('likes') && $request->likes == true;
$showCaption = $request->filled('caption') && $request->caption !== false;
$layout = $request->filled('layout') && $request->layout == 'compact' ? 'compact' : 'full';

View File

@ -4,114 +4,115 @@ namespace App\Jobs\FollowPipeline;
use App\Follower;
use App\FollowRequest;
use App\Jobs\HomeFeedPipeline\FeedUnfollowPipeline;
use App\Notification;
use App\Profile;
use App\Services\AccountService;
use App\Services\FollowerService;
use App\Services\NotificationService;
use Cache;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Log;
use Illuminate\Support\Facades\Redis;
use App\Services\AccountService;
use App\Services\FollowerService;
use App\Services\NotificationService;
use App\Jobs\HomeFeedPipeline\FeedUnfollowPipeline;
class UnfollowPipeline implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $actor;
protected $target;
protected $actor;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct($actor, $target)
{
$this->actor = $actor;
$this->target = $target;
}
protected $target;
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
$actor = $this->actor;
$target = $this->target;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct($actor, $target)
{
$this->actor = $actor;
$this->target = $target;
}
$actorProfile = Profile::find($actor);
if(!$actorProfile) {
return;
}
$targetProfile = Profile::find($target);
if(!$targetProfile) {
return;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
$actor = $this->actor;
$target = $this->target;
FeedUnfollowPipeline::dispatch($actor, $target)->onQueue('follow');
$actorProfile = Profile::find($actor);
if (! $actorProfile) {
return;
}
$targetProfile = Profile::find($target);
if (! $targetProfile) {
return;
}
FollowerService::remove($actor, $target);
FeedUnfollowPipeline::dispatch($actor, $target)->onQueue('follow');
$actorProfileSync = Cache::get(FollowerService::FOLLOWING_SYNC_KEY . $actor);
if(!$actorProfileSync) {
FollowServiceWarmCache::dispatch($actor)->onQueue('low');
} else {
if($actorProfile->following_count) {
$actorProfile->decrement('following_count');
} else {
$count = Follower::whereProfileId($actor)->count();
$actorProfile->following_count = $count;
$actorProfile->save();
}
Cache::put(FollowerService::FOLLOWING_SYNC_KEY . $actor, 1, 604800);
AccountService::del($actor);
}
FollowerService::remove($actor, $target);
$targetProfileSync = Cache::get(FollowerService::FOLLOWERS_SYNC_KEY . $target);
if(!$targetProfileSync) {
FollowServiceWarmCache::dispatch($target)->onQueue('low');
} else {
if($targetProfile->followers_count) {
$targetProfile->decrement('followers_count');
} else {
$count = Follower::whereFollowingId($target)->count();
$targetProfile->followers_count = $count;
$targetProfile->save();
}
Cache::put(FollowerService::FOLLOWERS_SYNC_KEY . $target, 1, 604800);
AccountService::del($target);
}
$actorProfileSync = Cache::get(FollowerService::FOLLOWING_SYNC_KEY.$actor);
if (! $actorProfileSync) {
FollowServiceWarmCache::dispatch($actor)->onQueue('low');
} else {
if ($actorProfile->following_count) {
$actorProfile->decrement('following_count');
} else {
$count = Follower::whereProfileId($actor)->count();
$actorProfile->following_count = $count;
$actorProfile->save();
}
Cache::put(FollowerService::FOLLOWING_SYNC_KEY.$actor, 1, 604800);
AccountService::del($actor);
}
if($targetProfile->domain == null) {
Notification::withTrashed()
->whereProfileId($target)
->whereAction('follow')
->whereActorId($actor)
->whereItemId($target)
->whereItemType('App\Profile')
->get()
->each(function($n) {
NotificationService::del($n->profile_id, $n->id);
$n->forceDelete();
});
}
$targetProfileSync = Cache::get(FollowerService::FOLLOWERS_SYNC_KEY.$target);
if (! $targetProfileSync) {
FollowServiceWarmCache::dispatch($target)->onQueue('low');
} else {
if ($targetProfile->followers_count) {
$targetProfile->decrement('followers_count');
} else {
$count = Follower::whereFollowingId($target)->count();
$targetProfile->followers_count = $count;
$targetProfile->save();
}
Cache::put(FollowerService::FOLLOWERS_SYNC_KEY.$target, 1, 604800);
AccountService::del($target);
}
if($actorProfile->domain == null && config('instance.timeline.home.cached')) {
Cache::forget('pf:timelines:home:' . $actor);
}
if ($targetProfile->domain == null) {
Notification::withTrashed()
->whereProfileId($target)
->whereAction('follow')
->whereActorId($actor)
->whereItemId($target)
->whereItemType('App\Profile')
->get()
->each(function ($n) {
NotificationService::del($n->profile_id, $n->id);
$n->forceDelete();
});
}
FollowRequest::whereFollowingId($target)
->whereFollowerId($actor)
->delete();
if ($actorProfile->domain == null && config('instance.timeline.home.cached')) {
Cache::forget('pf:timelines:home:'.$actor);
}
return;
}
FollowRequest::whereFollowingId($target)
->whereFollowerId($actor)
->delete();
AccountService::del($target);
AccountService::del($actor);
}
}

590
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -467,14 +467,14 @@ function await-database-ready()
case "${DB_CONNECTION:-}" in
mysql)
# shellcheck disable=SC2154
while ! echo "SELECT 1" | mysql --user="${DB_USERNAME}" --password="${DB_PASSWORD}" --host="${DB_HOST}" "${DB_DATABASE}" --silent >/dev/null; do
while ! echo "SELECT 1" | mysql --user="${DB_USERNAME}" --password="${DB_PASSWORD}" --host="${DB_HOST}" --port="${DOCKER_DB_HOST_PORT}" "${DB_DATABASE}" --silent >/dev/null; do
staggered-sleep
done
;;
pgsql)
# shellcheck disable=SC2154
while ! echo "SELECT 1" | PGPASSWORD="${DB_PASSWORD}" psql --user="${DB_USERNAME}" --host="${DB_HOST}" "${DB_DATABASE}" >/dev/null; do
while ! echo "SELECT 1" | PGPASSWORD="${DB_PASSWORD}" psql --user="${DB_USERNAME}" --host="${DB_HOST}" --port="${DOCKER_DB_HOST_PORT}" "${DB_DATABASE}" >/dev/null; do
staggered-sleep
done
;;

1381
package-lock.json generated

File diff suppressed because it is too large Load Diff

2
public/css/spa.css vendored

File diff suppressed because one or more lines are too long

2
public/embed.js vendored
View File

@ -1 +1 @@
!function(){var e;e=function(){var e=[];window.addEventListener("message",function(t){var n=t.data||{};"setHeight"===n.type&&e[n.id]&&(e[n.id].height=n.height)}),[].forEach.call(document.querySelectorAll("iframe.pixelfed__embed"),function(t){t.scrolling="no",t.style.overflow="hidden",e.push(t);var n=e.length-1;t.onload=function(){t.contentWindow.postMessage({type:"setHeight",id:n},"*")},t.onload()})},-1!==["interactive","complete"].indexOf(document.readyState)?e():document.addEventListener("DOMContentLoaded",e)}();
!function(){var e;e=function(){var e=[];window.addEventListener("message",function(t){var n=t.data||{};"setHeight"===n.type&&e[n.id]&&(e[n.id].height=n.height)}),[].forEach.call(document.querySelectorAll("iframe.pixelfed__embed"),function(t){t.scrolling="no",t.style.overflow="hidden",e.push(t);var n=e.length-1;t.onload=function(){t.contentWindow.postMessage({type:"setHeight",id:n},"*")},t.onload()})},-1!==["interactive","complete"].indexOf(document.readyState)?e():document.addEventListener("DOMContentLoaded",e)}();

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

2
public/js/app.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

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

View File

@ -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(l=0;l<e.length;l++){for(var[n,o,t]=e[l],i=!0,c=0;c<n.length;c++)(!1&t||d>=t)&&Object.keys(a.O).every((e=>a.O[e](n[c])))?n.splice(c--,1):(i=!1,t<d&&(d=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]},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/"+{1179:"daci.chunk",1240:"discover~myhashtags.chunk",1645:"profile~following.bundle",2156:"dms.chunk",2966:"discover~hashtag.bundle",3688:"discover~serverfeed.chunk",4951:"home.chunk",6250:"discover~settings.chunk",6535:"discover.chunk",6740:"discover~memories.chunk",7399:"dms~message.chunk",7413:"error404.bundle",7521:"discover~findfriends.chunk",7744:"notifications.chunk",8087:"profile.chunk",8119:"i18n.bundle",8408:"post.chunk",8977:"profile~followers.bundle",9124:"compose.chunk",9919:"changelog.bundle"}[e]+"."+{1179:"34dc7bad3a0792cc",1240:"8886fc0d4736d819",1645:"7ca7cfa5aaae75e2",2156:"2b55effc0e8ba89f",2966:"a0f00fc7df1f313c",3688:"262bf7e3bce843c3",4951:"264eeb47bfac56c1",6250:"65d6f3cbe5323ed4",6535:"c2229e1d15bd3ada",6740:"37e0c325f900e163",7399:"976f7edaa6f71137",7413:"b397483e3991ab20",7521:"b1858bea66d9723b",7744:"0c5151643e4534aa",8087:"a2234f891ba86efd",8119:"93a02e275ac1a708",8408:"9184101a2b809af1",8977:"5d796e79f32d066c",9124:"a0cfdf07f5062445",9919:"bf44edbbfa14bd53"}[e]+".js",a.miniCssF=e=>({2305:"css/portfolio",2540:"css/landing",3364:"css/admin",6952:"css/appdark",8252:"css/app",8759:"css/spa"}[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 i,c;if(void 0!==t)for(var s=document.getElementsByTagName("script"),l=0;l<s.length;l++){var f=s[l];if(f.getAttribute("src")==e||f.getAttribute("data-webpack")==n+t){i=f;break}}i||(c=!0,(i=document.createElement("script")).charset="utf-8",i.timeout=120,a.nc&&i.setAttribute("nonce",a.nc),i.setAttribute("data-webpack",n+t),i.src=e),r[e]=[o];var u=(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(u.bind(null,void 0,{type:"timeout",target:i}),12e4);i.onerror=u.bind(null,i.onerror),i.onload=u.bind(null,i.onload),c&&document.head.appendChild(i)}},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={461:0,6952:0,8252:0,2305:0,3364:0,2540:0,8759: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(/^((69|82)52|2305|2540|3364|461|8759)$/.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),i=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;i.message="Loading chunk "+r+" failed.\n("+t+": "+d+")",i.name="ChunkLoadError",i.type=t,i.request=d,o[1](i)}}),"chunk-"+r,r)}},a.O.j=r=>0===e[r];var r=(r,n)=>{var o,t,[d,i,c]=n,s=0;if(d.some((r=>0!==e[r]))){for(o in i)a.o(i,o)&&(a.m[o]=i[o]);if(c)var l=c(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(l)},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 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(l=0;l<e.length;l++){for(var[n,o,t]=e[l],i=!0,c=0;c<n.length;c++)(!1&t||d>=t)&&Object.keys(a.O).every((e=>a.O[e](n[c])))?n.splice(c--,1):(i=!1,t<d&&(d=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]},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/"+{1179:"daci.chunk",1240:"discover~myhashtags.chunk",1645:"profile~following.bundle",2156:"dms.chunk",2966:"discover~hashtag.bundle",3688:"discover~serverfeed.chunk",4951:"home.chunk",6250:"discover~settings.chunk",6535:"discover.chunk",6740:"discover~memories.chunk",7399:"dms~message.chunk",7413:"error404.bundle",7521:"discover~findfriends.chunk",7744:"notifications.chunk",8087:"profile.chunk",8119:"i18n.bundle",8408:"post.chunk",8977:"profile~followers.bundle",9124:"compose.chunk",9919:"changelog.bundle"}[e]+"."+{1179:"e49239579f174211",1240:"25db2bcadb2836b5",1645:"9294aa1b560387c7",2156:"a42edfd973f6c593",2966:"1b11b46e0b28aa3f",3688:"4eb5e50270522771",4951:"8bbc3c5c38dde66d",6250:"3f3acf6b2d7f41a2",6535:"1404d3172761023b",6740:"315bb6896f3afec2",7399:"6cd795c99fc1a568",7413:"54601f9cdd0f7719",7521:"d0e638a697f821b4",7744:"1086603ea08d1017",8087:"33a4b9cb10dbbb6c",8119:"28bba3e12cdadf51",8408:"803d8c9f68415936",8977:"50a39058d98e16eb",9124:"47ba00abaa827b26",9919:"d5810c2672b6abc7"}[e]+".js",a.miniCssF=e=>({2305:"css/portfolio",2540:"css/landing",3364:"css/admin",6952:"css/appdark",8252:"css/app",8759:"css/spa"}[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 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,a.nc&&i.setAttribute("nonce",a.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)}},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={461:0,6952:0,8252:0,2305:0,3364:0,2540:0,8759: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(/^((69|82)52|2305|2540|3364|461|8759)$/.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),i=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;i.message="Loading chunk "+r+" failed.\n("+t+": "+d+")",i.name="ChunkLoadError",i.type=t,i.request=d,o[1](i)}}),"chunk-"+r,r)}},a.O.j=r=>0===e[r];var r=(r,n)=>{var o,t,[d,i,c]=n,s=0;if(d.some((r=>0!==e[r]))){for(o in i)a.o(i,o)&&(a.m[o]=i[o]);if(c)var l=c(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(l)},n=self.webpackChunkpixelfed=self.webpackChunkpixelfed||[];n.forEach(r.bind(null,0)),n.push=r.bind(null,n.push.bind(n))})(),a.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

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

2
public/js/vendor.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,11 +1,11 @@
{
"/js/app.js": "/js/app.js?id=d4fb3d91eb65298a439439305dd50dde",
"/js/app.js": "/js/app.js?id=3688fe4a647f902efc642afb1a50984e",
"/js/activity.js": "/js/activity.js?id=dea89d9571c6bd889dd0f51a154b3872",
"/js/components.js": "/js/components.js?id=ebf743614d3b943541f868a0bc3db9d8",
"/js/discover.js": "/js/discover.js?id=7c90d36829dfe34f19f5d1f545107db7",
"/js/profile.js": "/js/profile.js?id=daadd03b5dbf21aed9da191d2ddaaf09",
"/js/status.js": "/js/status.js?id=203ab55ba6796a2c40c856d935198f35",
"/js/timeline.js": "/js/timeline.js?id=ec7213d8adc45f4c3c8254a23d82eee7",
"/js/profile.js": "/js/profile.js?id=3525518f6fe5c963b9990836b1fc5255",
"/js/status.js": "/js/status.js?id=698e2cb5d324ebc4f238adc1dde67210",
"/js/timeline.js": "/js/timeline.js?id=6e17b91cb6203cff8a4daaba71eb42b1",
"/js/compose.js": "/js/compose.js?id=b91af90a8f7ffcebc23ac602a24f7d4c",
"/js/compose-classic.js": "/js/compose-classic.js?id=73f7993759f12417a544364c320e273b",
"/js/search.js": "/js/search.js?id=fd2788ca403610348dacddf102dcd532",
@ -16,40 +16,40 @@
"/js/profile-directory.js": "/js/profile-directory.js?id=1615064235d2acf08d84c3e3d1232d7e",
"/js/story-compose.js": "/js/story-compose.js?id=50d723634d8d22db14d630a02774e5b7",
"/js/direct.js": "/js/direct.js?id=2f7df211df1b62a0637ed87f2457e918",
"/js/admin.js": "/js/admin.js?id=6b704e46b54b8ec1b0600ff50b33f7b9",
"/js/spa.js": "/js/spa.js?id=cd6a07d612c09f17c34a6e8441768020",
"/js/admin.js": "/js/admin.js?id=0c438fd27a3e0ee99d0f2153295bcbfb",
"/js/spa.js": "/js/spa.js?id=81f014a7e6be725c0665d1a1c3d4f01d",
"/js/stories.js": "/js/stories.js?id=f3d502fa937e5fa90d173d5d7aa64e2c",
"/js/portfolio.js": "/js/portfolio.js?id=e8a1f57ef2c7c9ff40265502da5b84ac",
"/js/account-import.js": "/js/account-import.js?id=c17bc3e351e51eb64529a4b28c75d9d4",
"/js/portfolio.js": "/js/portfolio.js?id=d53caf31d3ef87b47fbc51a31ff943f8",
"/js/account-import.js": "/js/account-import.js?id=1d1d10a8a9ea46e9a66219ea6dc4c803",
"/js/admin_invite.js": "/js/admin_invite.js?id=0a0036f59cfb186f7698207ae432365b",
"/js/landing.js": "/js/landing.js?id=753a52aacb8bb884f50ed3ae9ed99a38",
"/js/landing.js": "/js/landing.js?id=d62950f5ece78070ffd1ffdcc38f687b",
"/js/remote_auth.js": "/js/remote_auth.js?id=37e5bdf3bc1896eee063db7a186b9876",
"/js/manifest.js": "/js/manifest.js?id=1aecad6992ea1cdb8054608c3604a5cc",
"/js/home.chunk.264eeb47bfac56c1.js": "/js/home.chunk.264eeb47bfac56c1.js?id=c5704eda3f241103f1ed1fa6fa4cefad",
"/js/compose.chunk.a0cfdf07f5062445.js": "/js/compose.chunk.a0cfdf07f5062445.js?id=71f4bcf44739473ee369521ea785f63e",
"/js/post.chunk.9184101a2b809af1.js": "/js/post.chunk.9184101a2b809af1.js?id=b24c0c9949fba5b3e76cb95ea8bb6e5a",
"/js/profile.chunk.a2234f891ba86efd.js": "/js/profile.chunk.a2234f891ba86efd.js?id=2c9f83cb28d3893a169200c8341dbbb1",
"/js/discover~memories.chunk.37e0c325f900e163.js": "/js/discover~memories.chunk.37e0c325f900e163.js?id=02137ba179f0f2f3819597f262f423b8",
"/js/discover~myhashtags.chunk.8886fc0d4736d819.js": "/js/discover~myhashtags.chunk.8886fc0d4736d819.js?id=0397f095e24b2bbdffd84be14bb9d8c4",
"/js/daci.chunk.34dc7bad3a0792cc.js": "/js/daci.chunk.34dc7bad3a0792cc.js?id=53da4c2b40ecc1164592bd0f66767284",
"/js/discover~findfriends.chunk.b1858bea66d9723b.js": "/js/discover~findfriends.chunk.b1858bea66d9723b.js?id=3be5b1f07a6fa6a52efae3165391c328",
"/js/discover~serverfeed.chunk.262bf7e3bce843c3.js": "/js/discover~serverfeed.chunk.262bf7e3bce843c3.js?id=4b8b7ab8f27e79fc4eef11c08ec9cbf8",
"/js/discover~settings.chunk.65d6f3cbe5323ed4.js": "/js/discover~settings.chunk.65d6f3cbe5323ed4.js?id=2f1be9f65c1abe119e7283fbb6a9c1c3",
"/js/discover.chunk.c2229e1d15bd3ada.js": "/js/discover.chunk.c2229e1d15bd3ada.js?id=a88392222bc4cd0ea8183980da6f6402",
"/js/notifications.chunk.0c5151643e4534aa.js": "/js/notifications.chunk.0c5151643e4534aa.js?id=f3239550ec43ea4ff0a0c841a8d6179f",
"/js/dms.chunk.2b55effc0e8ba89f.js": "/js/dms.chunk.2b55effc0e8ba89f.js?id=a97c2bb5c33a8265397f5712abc5d7f0",
"/js/dms~message.chunk.976f7edaa6f71137.js": "/js/dms~message.chunk.976f7edaa6f71137.js?id=5cd8c66f0cc7b483d3d848b9f24f0227",
"/js/profile~followers.bundle.5d796e79f32d066c.js": "/js/profile~followers.bundle.5d796e79f32d066c.js?id=7a607d5976217c7d5f7ca6784447b783",
"/js/profile~following.bundle.7ca7cfa5aaae75e2.js": "/js/profile~following.bundle.7ca7cfa5aaae75e2.js?id=8d3cf326f5f5a6a6e129f0148b6b69d1",
"/js/discover~hashtag.bundle.a0f00fc7df1f313c.js": "/js/discover~hashtag.bundle.a0f00fc7df1f313c.js?id=4bc97210a5b792f40c9c3516102fa23e",
"/js/error404.bundle.b397483e3991ab20.js": "/js/error404.bundle.b397483e3991ab20.js?id=d670737f4f52f3ecac26865c18cc585d",
"/js/i18n.bundle.93a02e275ac1a708.js": "/js/i18n.bundle.93a02e275ac1a708.js?id=945ffd7c76a92fbb5ab17c88f26ec739",
"/js/changelog.bundle.bf44edbbfa14bd53.js": "/js/changelog.bundle.bf44edbbfa14bd53.js?id=37af1fdc9f4a3226227946db8452eb52",
"/js/manifest.js": "/js/manifest.js?id=4e958b1146e4f0430a79b2e37adb0ee5",
"/js/home.chunk.8bbc3c5c38dde66d.js": "/js/home.chunk.8bbc3c5c38dde66d.js?id=2d0f1bd43e0ac2372493198a919d4c4f",
"/js/compose.chunk.47ba00abaa827b26.js": "/js/compose.chunk.47ba00abaa827b26.js?id=9670e07da2a58c201dfee2ed8d5308a1",
"/js/post.chunk.803d8c9f68415936.js": "/js/post.chunk.803d8c9f68415936.js?id=509a232386771d60e1fa32ed3c56a2b4",
"/js/profile.chunk.33a4b9cb10dbbb6c.js": "/js/profile.chunk.33a4b9cb10dbbb6c.js?id=62c0e217dba5a38d1a60fc08d6273b09",
"/js/discover~memories.chunk.315bb6896f3afec2.js": "/js/discover~memories.chunk.315bb6896f3afec2.js?id=a8bd9bc76eb0339a4eef06219fe7b513",
"/js/discover~myhashtags.chunk.25db2bcadb2836b5.js": "/js/discover~myhashtags.chunk.25db2bcadb2836b5.js?id=a9fe5b8f9aee962bb3df2b67af9294a4",
"/js/daci.chunk.e49239579f174211.js": "/js/daci.chunk.e49239579f174211.js?id=856de905931148b8ece9d57eebaf053c",
"/js/discover~findfriends.chunk.d0e638a697f821b4.js": "/js/discover~findfriends.chunk.d0e638a697f821b4.js?id=18b9be879d96a7fa7d3e78cc86fd75c9",
"/js/discover~serverfeed.chunk.4eb5e50270522771.js": "/js/discover~serverfeed.chunk.4eb5e50270522771.js?id=a2c5f363ee3d238eb377b6fa6c48964b",
"/js/discover~settings.chunk.3f3acf6b2d7f41a2.js": "/js/discover~settings.chunk.3f3acf6b2d7f41a2.js?id=d6695dd4bd366e3500e05834c2c1be2b",
"/js/discover.chunk.1404d3172761023b.js": "/js/discover.chunk.1404d3172761023b.js?id=64614afd8b4dc2e723d4be94f95269ee",
"/js/notifications.chunk.1086603ea08d1017.js": "/js/notifications.chunk.1086603ea08d1017.js?id=2b9a342745dfc15efee64a36479ec25b",
"/js/dms.chunk.a42edfd973f6c593.js": "/js/dms.chunk.a42edfd973f6c593.js?id=d145d14e3d6e42f2b0c48807a302d068",
"/js/dms~message.chunk.6cd795c99fc1a568.js": "/js/dms~message.chunk.6cd795c99fc1a568.js?id=84ebbb0bf9d25931c8a45573105688c6",
"/js/profile~followers.bundle.50a39058d98e16eb.js": "/js/profile~followers.bundle.50a39058d98e16eb.js?id=9464465b46bf93aa995f4f3ab6fa7e84",
"/js/profile~following.bundle.9294aa1b560387c7.js": "/js/profile~following.bundle.9294aa1b560387c7.js?id=7bf7b38c9b2967772cfce6a4871549b8",
"/js/discover~hashtag.bundle.1b11b46e0b28aa3f.js": "/js/discover~hashtag.bundle.1b11b46e0b28aa3f.js?id=a3130c4a838b9c7bbae2cb03dc2d6465",
"/js/error404.bundle.54601f9cdd0f7719.js": "/js/error404.bundle.54601f9cdd0f7719.js?id=d670737f4f52f3ecac26865c18cc585d",
"/js/i18n.bundle.28bba3e12cdadf51.js": "/js/i18n.bundle.28bba3e12cdadf51.js?id=63ef9390fe1b3c652bb4dbff0ebf11ab",
"/js/changelog.bundle.d5810c2672b6abc7.js": "/js/changelog.bundle.d5810c2672b6abc7.js?id=e00d3c004ad5274caac3ba360c734dc2",
"/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=20cdb9cce61b0e1bd9fb1aad30efcd2f",
"/css/landing.css": "/css/landing.css?id=589f3fa192867727925921b0f68ce022",
"/css/spa.css": "/css/spa.css?id=24b025007b418a7e7efd18d47fa56b85",
"/js/vendor.js": "/js/vendor.js?id=9e8c3caac2c4d0119e99070a0bb36dfc"
"/css/spa.css": "/css/spa.css?id=489dcce2f610f29cf967756288d13647",
"/js/vendor.js": "/js/vendor.js?id=a18881f6b7437334b43dc693a83ecaea"
}

File diff suppressed because it is too large Load Diff

View File

@ -169,7 +169,7 @@
<script type="text/javascript">
import BigPicture from 'bigpicture';
import ReadMore from './ReadMore.vue';
import VideoPlayer from './../../presenter/VideoPlayer.vue';
import VideoPlayer from '@/presenter/VideoPlayer.vue';
export default {
props: ['status'],

View File

@ -0,0 +1,75 @@
<template>
<div v-if="status.sensitive == true">
<details class="details-animated">
<summary>
<p class="mb-0 lead font-weight-bold">{{ status.spoiler_text ? status.spoiler_text : 'CW / NSFW / Hidden Media'}}</p>
<p class="font-weight-light">(click to show)</p>
</summary>
<b-carousel :id="status.id + '-carousel'"
style="text-shadow: 1px 1px 2px #333; background-color: #000;"
controls
img-blank
background="#ffffff"
:interval="0"
>
<b-carousel-slide v-for="(media, index) in status.media_attachments" :key="media.id + '-media'">
<video v-if="media.type == 'video'" slot="img" class="embed-responsive-item" preload="none" controls playsinline loop :alt="media.description" width="100%" height="100%">
<source :src="media.url" :type="media.mime">
</video>
<div v-else-if="media.type == 'image'" slot="img" :title="media.description">
<img :class="media.filter_class + ' d-block img-fluid w-100'" :src="media.url" :alt="media.description" loading="lazy" onerror="this.onerror=null;this.src='/storage/no-preview.png'">
</div>
<p v-else class="text-center p-0 font-weight-bold text-white">Error: Problem rendering preview.</p>
</b-carousel-slide>
</b-carousel>
</details>
</div>
<div v-else class="w-100 h-100 p-0">
<!-- <b-carousel :id="status.id + '-carousel'"
style="text-shadow: 1px 1px 2px #333; background-color: #000;"
controls
img-blank
background="#ffffff"
:interval="0"
>
<b-carousel-slide v-for="(media, index) in status.media_attachments" :key="media.id + '-media'">
<video v-if="media.type == 'Video'" slot="img" class="embed-responsive-item" preload="none" controls loop :title="media.description" width="100%" height="100%" :poster="media.preview_url">
<source :src="media.url" :type="media.mime">
</video>
<div v-else-if="media.type == 'Image'" slot="img" :title="media.description">
<img :class="media.filter_class + ' d-block img-fluid w-100'" :src="media.url" :alt="media.description" loading="lazy">
</div>
<p v-else class="text-center p-0 font-weight-bold text-white">Error: Problem rendering preview.</p>
</b-carousel-slide>
</b-carousel> -->
<carousel ref="carousel" :centerMode="true" :loop="false" :per-page="1" :paginationPosition="'bottom-overlay'" paginationActiveColor="#3897f0" paginationColor="#dbdbdb" class="p-0 m-0">
<slide v-for="(media, index) in status.media_attachments" :key="'px-carousel-'+media.id + '-' + index" class="w-100 h-100 d-block mx-auto text-center" style="background: #000; display: flex;align-items: center;">
<video v-if="media.type == 'video'" class="embed-responsive-item" preload="none" controls loop :title="media.description" width="100%" height="100%">
<source :src="media.url" :type="media.mime">
</video>
<div v-else-if="media.type == 'image'" :title="media.description">
<img :class="media.filter_class + ' img-fluid w-100'" :src="media.url" :alt="media.description" loading="lazy" onerror="this.onerror=null;this.src='/storage/no-preview.png'">
</div>
<p v-else class="text-center p-0 font-weight-bold text-white">Error: Problem rendering preview.</p>
</slide>
</carousel>
</div>
</template>
<script type="text/javascript">
export default {
props: ['status']
}
</script>

View File

@ -0,0 +1,188 @@
<template>
<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 album may contain sensitive content.'}}
</p>
<p class="mb-0">
<button @click="toggleContentWarning()" class="btn btn-outline-light btn-block btn-sm font-weight-bold">See Post</button>
</p>
</div>
<blur-hash-image
width="32"
height="32"
:punch="1"
:hash="status.media_attachments[0].blurhash"
:alt="altText(status)"/>
</div>
<div v-else class="w-100 h-100 p-0 album-wrapper">
<carousel ref="carousel" :centerMode="true" :loop="false" :per-page="1" :paginationPosition="'bottom-overlay'" paginationActiveColor="#3897f0" paginationColor="#dbdbdb" class="p-0 m-0" :id="'carousel-' + status.id">
<slide v-for="(img, index) in status.media_attachments" :key="'px-carousel-'+img.id + '-' + index" class="" style="background: #000; display: flex;align-items: center;" :title="img.description">
<img
class="img-fluid w-100 p-0"
:src="img.url"
:alt="altText(img)"
loading="lazy"
:data-bp="img.url"
onerror="this.onerror=null;this.src='/storage/no-preview.png'">
</slide>
</carousel>
<div class="album-overlay">
<p v-if="!status.sensitive && sensitive"
@click="status.sensitive = true"
style="
margin-top: 0;
padding: 10px;
color: #fff;
font-size: 10px;
text-align: right;
position: absolute;
top: 0;
right: 0;
border-top-left-radius: 5px;
cursor: pointer;
background: linear-gradient(0deg, rgba(0,0,0,0.5), rgba(0,0,0,0.5));
">
<i class="fas fa-eye-slash fa-lg"></i>
</p>
<p @click.prevent="toggleLightbox"
style="
margin-top: 0;
padding: 10px;
color: #fff;
font-size: 10px;
text-align: right;
position: absolute;
left: 0;
top: 0;
border-bottom-right-radius: 5px;
cursor: pointer;
background: linear-gradient(0deg, rgba(0,0,0,0.5), rgba(0,0,0,0.5));
">
<i class="fas fa-expand fa-lg"></i>
</p>
<p
v-if="status.media_attachments[0].license"
style="
margin-bottom: 0;
padding: 0 5px;
color: #fff;
font-size: 10px;
text-align: right;
position: absolute;
bottom: 0;
right: 0;
border-top-left-radius: 5px;
background: linear-gradient(0deg, rgba(0,0,0,0.5), rgba(0,0,0,0.5));
">
<a :href="status.url" class="font-weight-bold text-light">Photo</a> by <a :href="status.account.url" class="font-weight-bold text-light">&commat;{{status.account.username}}</a> licensed under <a :href="status.media_attachments[0].license.url" class="font-weight-bold text-light">{{status.media_attachments[0].license.title}}</a>
</p>
</div>
</div>
</template>
<script type="text/javascript">
import BigPicture from 'bigpicture';
export default {
props: ['status'],
data() {
return {
sensitive: this.status.sensitive,
cursor: 0
}
},
created() {
// window.addEventListener("keydown", this.keypressNavigation);
},
beforeDestroy() {
// window.removeEventListener("keydown", this.keypressNavigation);
},
methods: {
toggleContentWarning(status) {
this.$emit('togglecw');
},
toggleLightbox(e) {
BigPicture({
el: e.target,
gallery: '#carousel-' + this.status.id,
position: this.$refs.carousel.currentPage
})
},
altText(img) {
let desc = img.description;
if(desc) {
return desc;
}
return 'Photo was not tagged with any alt text.';
},
keypressNavigation(e) {
let ref = this.$refs.carousel;
if (e.keyCode == "37") {
e.preventDefault();
let direction = "backward";
ref.advancePage(direction);
ref.$emit("navigation-click", direction);
}
if (e.keyCode == "39") {
e.preventDefault();
let direction = "forward";
ref.advancePage(direction);
ref.$emit("navigation-click", direction);
}
}
}
}
</script>
<style type="text/css" scoped>
.card-img-top {
border-top-left-radius: 0 !important;
border-top-right-radius: 0 !important;
}
.content-label-wrapper {
position: relative;
}
.content-label {
margin: 0;
position: absolute;
top:50%;
left:50%;
transform: translate(-50%, -50%);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
z-index: 2;
background: rgba(0, 0, 0, 0.2)
}
.album-wrapper {
position: relative;
}
</style>

View File

@ -0,0 +1,160 @@
<template>
<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="toggleContentWarning()" class="btn btn-outline-light btn-block btn-sm font-weight-bold">See Post</button>
</p>
</div>
<blur-hash-image
width="32"
height="32"
:punch="1"
:hash="status.media_attachments[0].blurhash"
:alt="altText(status)"/>
</div>
<div v-else>
<div :title="status.media_attachments[0].description" style="position: relative;">
<img class="card-img-top"
:src="status.media_attachments[0].url"
loading="lazy"
:alt="altText(status)"
:width="width()"
:height="height()"
onerror="this.onerror=null;this.src='/storage/no-preview.png'"
@click.prevent="toggleLightbox">
<!-- <blur-hash-image
class="card-img-top"
width="32"
height="32"
:punch="1"
:hash="status.media_attachments[0].blurhash"
:src="status.media_attachments[0].url"
:alt="altText(status)"
@click.prevent="toggleLightbox"/> -->
<p v-if="!status.sensitive && sensitive"
@click="status.sensitive = true"
style="
margin-top: 0;
padding: 10px;
color: #fff;
font-size: 10px;
text-align: right;
position: absolute;
top: 0;
right: 0;
border-top-left-radius: 5px;
cursor: pointer;
background: linear-gradient(0deg, rgba(0,0,0,0.5), rgba(0,0,0,0.5));
">
<i class="fas fa-eye-slash fa-lg"></i>
</p>
<p
v-if="status.media_attachments[0].license"
style="
margin-bottom: 0;
padding: 0 5px;
color: #fff;
font-size: 10px;
text-align: right;
position: absolute;
bottom: 0;
right: 0;
border-top-left-radius: 5px;
background: linear-gradient(0deg, rgba(0,0,0,0.5), rgba(0,0,0,0.5));
"><a :href="status.url" class="font-weight-bold text-light">Photo</a> by <a :href="status.account.url" class="font-weight-bold text-light">&commat;{{status.account.username}}</a> licensed under <a :href="status.media_attachments[0].license.url" class="font-weight-bold text-light">{{status.media_attachments[0].license.title}}</a></p>
</div>
</div>
</template>
<style type="text/css" scoped>
.card-img-top {
border-top-left-radius: 0 !important;
border-top-right-radius: 0 !important;
}
.content-label-wrapper {
position: relative;
}
.content-label {
margin: 0;
position: absolute;
top:50%;
left:50%;
transform: translate(-50%, -50%);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
z-index: 2;
background: rgba(0, 0, 0, 0.2)
}
</style>
<script type="text/javascript">
import BigPicture from 'bigpicture';
export default {
props: ['status'],
data() {
return {
sensitive: this.status.sensitive
}
},
mounted() {
},
methods: {
altText(status) {
let desc = status.media_attachments[0].description;
if(desc) {
return desc;
}
return 'Photo was not tagged with any alt text.';
},
toggleContentWarning(status) {
this.$emit('togglecw');
},
toggleLightbox(e) {
BigPicture({
el: e.target
})
},
width() {
if( !this.status.media_attachments[0].meta ||
!this.status.media_attachments[0].meta.original ||
!this.status.media_attachments[0].meta.original.width ) {
return;
}
return this.status.media_attachments[0].meta.original.width;
},
height() {
if( !this.status.media_attachments[0].meta ||
!this.status.media_attachments[0].meta.original ||
!this.status.media_attachments[0].meta.original.height ) {
return;
}
return this.status.media_attachments[0].meta.original.height;
}
}
}
</script>

View File

@ -0,0 +1,44 @@
<template>
<div v-if="status.sensitive == true">
<details class="details-animated">
<summary>
<p class="mb-0 lead font-weight-bold">{{ status.spoiler_text ? status.spoiler_text : 'CW / NSFW / Hidden Media'}}</p>
<p class="font-weight-light">(click to show)</p>
</summary>
<b-carousel :id="status.id + '-carousel'"
style="text-shadow: 1px 1px 2px #333; background-color: #000;"
controls
img-blank
background="#ffffff"
:interval="0"
>
<b-carousel-slide v-for="(vid, index) in status.media_attachments" :key="vid.id + '-media'">
<video slot="img" class="embed-responsive-item" preload="none" controls playsinline loop :alt="vid.description" width="100%" height="100%">
<source :src="vid.url" :type="vid.mime">
</video>
</b-carousel-slide>
</b-carousel>
</details>
</div>
<div v-else>
<b-carousel :id="status.id + '-carousel'"
style="text-shadow: 1px 1px 2px #333; background-color: #000;"
controls
img-blank
background="#ffffff"
:interval="0"
>
<b-carousel-slide v-for="(vid, index) in status.media_attachments" :key="vid.id + '-media'">
<video slot="img" class="embed-responsive-item" preload="none" controls playsinline loop :alt="vid.description" width="100%" height="100%">
<source :src="vid.url" :type="vid.mime">
</video>
</b-carousel-slide>
</b-carousel>
</div>
</template>
<script type="text/javascript">
export default {
props: ['status']
}
</script>

View File

@ -29,10 +29,10 @@
</div>
<template v-else>
<video v-if="hasHls" ref="video" :class="{ fixedHeight: fixedHeight }" style="margin:0" playsinline controls autoplay="false" :poster="getPoster(status)">
<video v-if="hasHls" ref="video" :class="{ fixedHeight: fixedHeight }" style="margin:0" playsinline webkit-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)">
<video v-else class="card-img-top shadow" :class="{ fixedHeight: fixedHeight }" style="border-radius:15px;object-fit: contain;background-color: #000;" autoplay="false" playsinline webkit-playsinline controls :poster="getPoster(status)">
<source :src="status.media_attachments[0].url" :type="status.media_attachments[0].mime">
</video>
</template>

View File

@ -0,0 +1,90 @@
<template>
<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="toggleContentWarning()" class="btn btn-outline-light btn-block btn-sm font-weight-bold">See Post</button>
</p>
</div>
<blur-hash-image
width="32"
height="32"
:punch="1"
:hash="status.media_attachments[0].blurhash"
:alt="altText(status)"/>
</div>
<div v-else class="embed-responsive embed-responsive-16by9">
<video class="video" controls playsinline webkit-playsinline preload="metadata" loop :data-id="status.id" :poster="poster()">
<source :src="status.media_attachments[0].url" :type="status.media_attachments[0].mime">
</video>
</div>
</template>
<style type="text/css" scoped>
.content-label-wrapper {
position: relative;
}
.content-label {
margin: 0;
position: absolute;
top:50%;
left:50%;
transform: translate(-50%, -50%);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
z-index: 2;
background: rgba(0, 0, 0, 0.2)
}
</style>
<script type="text/javascript">
export default {
props: ['status'],
methods: {
altText(status) {
let desc = status.media_attachments[0].description;
if(desc) {
return desc;
}
return 'Video was not tagged with any alt text.';
},
playOrPause(e) {
let el = e.target;
if(el.getAttribute('playing') == 1) {
el.removeAttribute('playing');
el.pause();
} else {
el.setAttribute('playing', 1);
el.play();
}
},
toggleContentWarning(status) {
this.$emit('togglecw');
},
poster() {
let url = this.status.media_attachments[0].preview_url;
if(url.endsWith('no-preview.jpg') || url.endsWith('no-preview.png')) {
return;
}
return url;
}
}
}
</script>

View File

@ -91,6 +91,8 @@
v-on:delete="deletePost"
v-on:report-modal="handleReport"
v-on:edit="handleEdit"
v-on:muted="handleMuted"
v-on:unfollow="handleUnfollow"
/>
<likes-modal
@ -543,6 +545,7 @@
deletePost() {
this.feed.splice(this.postIndex, 1);
this.forceUpdateIdx++;
},
counterChange(index, type) {
@ -788,6 +791,21 @@
.then(res => {
})
},
handleMuted(post) {
this.feed = this.feed.filter(p => {
return p.account.id !== post.account.id;
});
},
handleUnfollow(post) {
if(this.scope === 'home') {
this.feed = this.feed.filter(p => {
return p.account.id !== post.account.id;
});
}
this.updateProfile({ following_count: this.profile.following_count - 1 });
},
},
watch: {

View File

@ -22,7 +22,7 @@
:alt="altText(status)"/>
</div>
<div v-else class="embed-responsive embed-responsive-16by9">
<video class="video" controls playsinline preload="metadata" loop :data-id="status.id" :poster="poster()">
<video class="video" controls playsinline webkit-playsinline preload="metadata" loop :data-id="status.id" :poster="poster()">
<source :src="status.media_attachments[0].url" :type="status.media_attachments[0].mime">
</video>
</div>

View File

@ -48,27 +48,27 @@ Vue.use(VueTimeago, {
Vue.component(
'photo-presenter',
require('./components/presenter/PhotoPresenter.vue').default
require('./../components/presenter/PhotoPresenter.vue').default
);
Vue.component(
'video-presenter',
require('./components/presenter/VideoPresenter.vue').default
require('./../components/presenter/VideoPresenter.vue').default
);
Vue.component(
'photo-album-presenter',
require('./components/presenter/PhotoAlbumPresenter.vue').default
require('./../components/presenter/PhotoAlbumPresenter.vue').default
);
Vue.component(
'video-album-presenter',
require('./components/presenter/VideoAlbumPresenter.vue').default
require('./../components/presenter/VideoAlbumPresenter.vue').default
);
Vue.component(
'mixed-album-presenter',
require('./components/presenter/MixedAlbumPresenter.vue').default
require('./../components/presenter/MixedAlbumPresenter.vue').default
);
Vue.component(

View File

@ -1,26 +1,26 @@
Vue.component(
'photo-presenter',
require('./components/presenter/PhotoPresenter.vue').default
require('./../components/presenter/PhotoPresenter.vue').default
);
Vue.component(
'video-presenter',
require('./components/presenter/VideoPresenter.vue').default
require('./../components/presenter/VideoPresenter.vue').default
);
Vue.component(
'photo-album-presenter',
require('./components/presenter/PhotoAlbumPresenter.vue').default
require('./../components/presenter/PhotoAlbumPresenter.vue').default
);
Vue.component(
'video-album-presenter',
require('./components/presenter/VideoAlbumPresenter.vue').default
require('./../components/presenter/VideoAlbumPresenter.vue').default
);
Vue.component(
'mixed-album-presenter',
require('./components/presenter/MixedAlbumPresenter.vue').default
require('./../components/presenter/MixedAlbumPresenter.vue').default
);
Vue.component(

View File

@ -60,27 +60,27 @@ Vue.component(
Vue.component(
'photo-presenter',
require('./components/presenter/PhotoPresenter.vue').default
require('./../components/presenter/PhotoPresenter.vue').default
);
Vue.component(
'video-presenter',
require('./components/presenter/VideoPresenter.vue').default
require('./../components/presenter/VideoPresenter.vue').default
);
Vue.component(
'photo-album-presenter',
require('./components/presenter/PhotoAlbumPresenter.vue').default
require('./../components/presenter/PhotoAlbumPresenter.vue').default
);
Vue.component(
'video-album-presenter',
require('./components/presenter/VideoAlbumPresenter.vue').default
require('./../components/presenter/VideoAlbumPresenter.vue').default
);
Vue.component(
'mixed-album-presenter',
require('./components/presenter/MixedAlbumPresenter.vue').default
require('./../components/presenter/MixedAlbumPresenter.vue').default
);
Vue.component(

View File

@ -1,26 +1,26 @@
Vue.component(
'photo-presenter',
require('./components/presenter/PhotoPresenter.vue').default
require('./../components/presenter/PhotoPresenter.vue').default
);
Vue.component(
'video-presenter',
require('./components/presenter/VideoPresenter.vue').default
require('./../components/presenter/VideoPresenter.vue').default
);
Vue.component(
'photo-album-presenter',
require('./components/presenter/PhotoAlbumPresenter.vue').default
require('./../components/presenter/PhotoAlbumPresenter.vue').default
);
Vue.component(
'video-album-presenter',
require('./components/presenter/VideoAlbumPresenter.vue').default
require('./../components/presenter/VideoAlbumPresenter.vue').default
);
Vue.component(
'mixed-album-presenter',
require('./components/presenter/MixedAlbumPresenter.vue').default
require('./../components/presenter/MixedAlbumPresenter.vue').default
);
Vue.component(
@ -32,3 +32,13 @@ Vue.component(
'post-component',
require('./components/PostComponent.vue').default
);
// Vue.component(
// 'post-next',
// require('./components/PostNext.vue').default
// );
// Vue.component(
// 'video-component',
// require('./components/VideoComponent.vue').default
// );

View File

@ -5,27 +5,27 @@ Vue.component(
Vue.component(
'photo-presenter',
require('./components/presenter/PhotoPresenter.vue').default
require('./../components/presenter/PhotoPresenter.vue').default
);
Vue.component(
'video-presenter',
require('./components/presenter/VideoPresenter.vue').default
require('./../components/presenter/VideoPresenter.vue').default
);
Vue.component(
'photo-album-presenter',
require('./components/presenter/PhotoAlbumPresenter.vue').default
require('./../components/presenter/PhotoAlbumPresenter.vue').default
);
Vue.component(
'video-album-presenter',
require('./components/presenter/VideoAlbumPresenter.vue').default
require('./../components/presenter/VideoAlbumPresenter.vue').default
);
Vue.component(
'mixed-album-presenter',
require('./components/presenter/MixedAlbumPresenter.vue').default
require('./../components/presenter/MixedAlbumPresenter.vue').default
);
Vue.component(
@ -46,4 +46,4 @@ Vue.component(
Vue.component(
'story-component',
require('./components/StoryTimelineComponent.vue').default
);
);

View File

@ -189,6 +189,10 @@ a.text-dark:hover {
.border {
border: 1px solid var(--border-color) !important;
&-right {
border-color: var(--border-color) !important;
}
}
.bg-white,
@ -396,6 +400,10 @@ span.twitter-typeahead .tt-suggestion:focus {
color: var(--dark);
}
.modal-backdrop {
opacity: 0.8;
}
.timeline-status-component {
.username {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

View File

@ -1,118 +1,108 @@
<!DOCTYPE html>
<html lang="{{ app()->getLocale() }}">
<head>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="mobile-web-app-capable" content="yes">
<title>{{ $title ?? config('app.name', 'Pixelfed') }}</title>
<title>{{ $title ?? config_cache('app.name', 'Pixelfed') }}</title>
<meta property="og:site_name" content="{{ config_cache('app.name', 'pixelfed') }}">
<meta property="og:title" content="{{ $title ?? config_cache('app.name', 'pixelfed') }}">
<meta property="og:type" content="article">
<meta property="og:type" content="profile">
<meta property="og:url" content="{{$profile['url']}}">
<meta name="medium" content="image">
<meta name="theme-color" content="#10c5f8">
<meta name="apple-mobile-web-app-capable" content="yes">
<link rel="shortcut icon" type="image/png" href="{{url('/img/favicon.png?v=2')}}">
<link rel="apple-touch-icon" type="image/png" href="{{url('/img/favicon.png?v=2')}}">
<link href="{{ mix('css/app.css') }}" rel="stylesheet">
<style type="text/css">
body.embed-card {
background: #fff !important;
margin: 0;
padding-bottom: 0;
}
.status-card-embed {
box-shadow: none;
border-radius: 4px;
overflow: hidden;
}
</style>
<style>.btn,img{vertical-align:middle}.btn,a{background-color:transparent}.btn:hover,a{text-decoration:none}.card,.col-4,.info-overlay,.square{position:relative}*,::after,::before{box-sizing:border-box}p{margin-top:0;margin-bottom:1rem}a{color:#2c78bf}a:hover{color:#1e5181;text-decoration:underline}img{border-style:none}.small{font-size:.875em;font-weight:400}.btn,body{font-size:.9rem;font-weight:400;line-height:1.6;color:#212529}.row{display:flex;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.col-4{width:100%;padding-right:15px;padding-left:15px;flex:0 0 33.33333333%;max-width:33.33333333%}.btn{display:inline-block;text-align:center;-webkit-user-select:none;-moz-user-select:none;user-select:none;border:1px solid transparent;padding:.375rem .75rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}.card,body{display:flex}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:#212529}.btn:focus{outline:0;box-shadow:0 0 0 .2rem rgba(44,120,191,.25)}.btn-primary:focus,.btn-primary:not(:disabled):not(.disabled):active:focus{box-shadow:0 0 0 .2rem rgba(76,140,201,.5)}.btn:disabled{opacity:.65}.btn:not(:disabled):not(.disabled){cursor:pointer}.btn-primary,.btn-primary:disabled{color:#fff;background-color:#2c78bf;border-color:#2c78bf}.btn-primary:focus,.btn-primary:hover{background-color:#2564a0;border-color:#225e96;color:#fff}.btn-primary:not(:disabled):not(.disabled):active{color:#fff;background-color:#225e96;border-color:#20578b}.btn-sm{padding:.25rem .5rem;font-size:.7875rem;line-height:1.5;border-radius:.2rem}.card{flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card-body{flex:1 1 auto;min-height:1px;padding:1.25rem}.card-footer,.card-header{padding:.75rem 1.25rem;background-color:#fff}.card-header{margin-bottom:0;border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-footer{border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.bg-white{background-color:#fff!important}.border{border:1px solid #dee2e6!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}.justify-content-between{justify-content:space-between!important}.align-items-center{align-items:center!important}.shadow-none{box-shadow:none!important}.mb-0{margin-bottom:0!important}.mb-1{margin-bottom:.25rem!important}.mt-2{margin-top:.5rem!important}.mt-4{margin-top:1.5rem!important}.px-0{padding-right:0!important;padding-left:0!important}.py-1{padding-top:.25rem!important}.pr-1,.px-1{padding-right:.25rem!important}.pb-1,.py-1{padding-bottom:.25rem!important}.px-1{padding-left:.25rem!important}.pl-2{padding-left:.5rem!important}.px-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.text-center{text-align:center!important}.text-uppercase{text-transform:uppercase!important}.font-weight-bold{font-weight:700!important}a.text-dark:focus,a.text-dark:hover{color:#000!important}a.text-muted:focus,a.text-muted:hover{color:#454b50!important}.text-muted{color:#6c757d!important}@media print{*,::after,::before{text-shadow:none!important;box-shadow:none!important}a:not(.btn){text-decoration:underline}img{page-break-inside:avoid}p{orphans:3;widows:3}body{min-width:992px!important}}body{margin:0;text-align:left;background-color:rgba(247,251,253,.4705882353);min-height:100vh;flex-flow:column;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif}.text-dark{color:#212529!important}.square{width:100%}.square::after{content:"";display:block;padding-bottom:100%}.square-content{position:absolute;width:100%;height:100%;background-repeat:no-repeat;background-size:cover;background-position:50%}@media (max-width:576px){.card-md-border-0{border-width:0!important;border-radius:0!important}.card-md-rounded-0{border-width:1px 0;border-radius:0!important}}.card{box-shadow:0 2px 6px 0 hsla(0,0%,0%,.2);border:none}body.embed-card{background:#fff!important;margin:0;padding-bottom:0}.status-card-embed{box-shadow:none;border-radius:4px;overflow:hidden}.avatar{border-radius:100%}</style>
</head>
<body class="bg-white">
<div class="embed-card">
<div class="card status-card-embed card-md-rounded-0 border">
<div class="card-header d-inline-flex align-items-center justify-content-between bg-white">
<div>
<img src="{{$profile['avatar']}}" width="32px" height="32px" style="border-radius: 32px;">
<a class="username font-weight-bold pl-2 text-dark" target="_blank" href="{{$profile['url']}}">
{{$profile['username']}}
</a>
</div>
<div>
<a class="small font-weight-bold text-muted pr-1" href="{{config('app.url')}}" target="_blank">{{config('pixelfed.domain.app')}}</a>
<img src="/img/pixelfed-icon-color.svg" width="26px">
<div class="embed-card">
<div class="card status-card-embed card-md-rounded-0 border">
<div class="card-header d-inline-flex align-items-center justify-content-between bg-white">
<div>
<img src="{{$profile['avatar']}}" width="32" height="32" class="avatar" onerror="this.onerror=null;this.src='/storage/avatars/default.jpg';">
<a class="username font-weight-bold pl-2 text-dark" target="_blank" href="{{$profile['url']}}">
{{$profile['username']}}
</a>
</div>
<div>
<a class="small font-weight-bold text-muted pr-1" href="{{config('app.url')}}" target="_blank">{{config('pixelfed.domain.app')}}</a>
<img src="/img/pixelfed-icon-color.svg" width="26" height="26">
</div>
</div>
<div class="card-body pb-1">
<div class="d-flex justify-content-between align-items-center">
<div class="text-center">
<p class="mb-0 font-weight-bold prettyCount" data-count="{{$profile['statuses_count']}}"></p>
<p class="mb-0 text-muted text-uppercase small font-weight-bold">Posts</p>
</div>
<div class="text-center">
<p class="mb-0 font-weight-bold prettyCount" data-count="{{$profile['followers_count']}}"></p>
<p class="mb-0 text-muted text-uppercase small font-weight-bold">Followers</p>
</div>
<div class="text-center">
<p class="mb-0"><a href="{{config('app.url')}}/i/intent/follow?user={{$profile['username']}}" class="btn btn-primary btn-sm py-1 px-4 text-uppercase font-weight-bold" target="_blank">Follow</a></p>
</div>
</div>
<div class="row mt-4 mb-1 embed-row"></div>
</div>
<div class="card-footer bg-white">
<p class="text-center mb-0">
<a href="{{$profile['url']}}" class="font-weight-bold" target="_blank">View More Posts</a>
</p>
</div>
</div>
</div>
</div>
<div class="card-body pb-1">
<div class="d-flex justify-content-between align-items-center">
<div class="text-center">
<p class="mb-0 font-weight-bold prettyCount" data-count="{{$profile['statuses_count']}}"></p>
<p class="mb-0 text-muted text-uppercase small font-weight-bold">Posts</p>
</div>
<div class="text-center">
<p class="mb-0 font-weight-bold prettyCount" data-count="{{$profile['followers_count']}}"></p>
<p class="mb-0 text-muted text-uppercase small font-weight-bold">Followers</p>
</div>
<div class="text-center">
<p class="mb-0"><a href="/i/intent/follow?user={{$profile['username']}}" class="btn btn-primary btn-sm py-1 px-4 text-uppercase font-weight-bold" target="_blank">Follow</a></p>
</div>
</div>
<div class="row mt-4 mb-1 embed-row"></div>
</div>
<div class="card-footer bg-white">
<p class="text-center mb-0">
<a href="{{$profile['url']}}" class="font-weight-bold" target="_blank">View More Posts</a>
</p>
</div>
</div>
</div>
<script type="text/javascript" src="{{mix('js/manifest.js')}}"></script>
<script type="text/javascript" src="{{mix('js/vendor.js')}}"></script>
<script type="text/javascript" src="{{mix('js/app.js')}}"></script>
<script type="text/javascript">
window.addEventListener("message", e=>{const t=e.data||{};});
</script>
<script type="text/javascript">document.querySelectorAll('.caption-container a').forEach(function(i) {i.setAttribute('target', '_blank');});</script>
<script type="text/javascript">
document.querySelectorAll('.prettyCount').forEach(function(i) {
i.innerText = App.util.format.count(i.getAttribute('data-count'));
});
</script>
<script type="text/javascript">
axios.get('/api/pixelfed/v1/accounts/{{$profile['id']}}/statuses', {
params: {
only_media: true,
limit: 24
}
})
.then(res => {
let parent = $('.embed-row');
res.data
.filter(res => res.pf_type == 'photo')
.filter(res => !res.sensitive)
.slice(0, 9)
.forEach(post => {
let el = `<div class="col-4 mt-2 px-0">
<a class="card info-overlay card-md-border-0 px-1 shadow-none" href="${post.url}" target="_blank">
<div class="square">
<div class="square-content" style="background-image: url('${post.media_attachments[0].url}')">
</div>
</div>
</a>
</div>`;
parent.append(el);
})
})
.finally(() => {
window.parent.postMessage({type:"setHeight",id:0,height:document.getElementsByTagName("html")[0].scrollHeight},"*");
setTimeout(() => {
window.parent.postMessage({type:"setHeight",id:0,height:document.getElementsByTagName("html")[0].scrollHeight},"*");
}, 5000);
})
</script>
<script type="text/javascript">
window.addEventListener("message", e=>{const t=e.data||{};});
document.querySelectorAll('.caption-container a').forEach(function(i) {i.setAttribute('target', '_blank');});
function formatCount(count = 0, locale = 'en-GB', notation = 'compact') {
if(count < 1) {
return 0;
}
return new Intl.NumberFormat(locale, { notation: notation , compactDisplay: "short" }).format(count);
}
function generateElements(html) {
const template = document.createElement('template');
template.innerHTML = html.trim();
return template.content.children;
}
document.querySelectorAll('.prettyCount').forEach(function(i) {
i.innerText = formatCount(i.getAttribute('data-count'));
});
fetch("{{config('app.url')}}/api/pixelfed/v1/accounts/{{$profile['id']}}/statuses?only_media=true&limit=24")
.then(res => res.json())
.then(res => {
let parent = document.querySelector('.embed-row');
res.filter(post => post.pf_type == 'photo' && !post.sensitive && post.visibility === 'public')
.slice(0, 9)
.forEach((post, idx) => {
let mediaUrl = post.media_attachments[0].preview_url ? post.media_attachments[0].preview_url : post.media_attachments[0].url;
let html = `<div class="col-4 mt-2 px-0"><a class="card info-overlay card-md-border-0 px-1 shadow-none" href="${post.url}" target="_blank"><div class="square"><div class="square-content" style="background-image: url('${mediaUrl}')"></div></div></a></div>`;
let el = document.createElement('div');
el.innerHTML = html;
parent.appendChild(el.firstChild);
});
})
window.addEventListener("message", e => {
const t = e.data || {};
if (window.parent && t.type === 'setHeight') {
updateHeight(t.id)
}
});
function updateHeight(id) {
setTimeout(() => {
window.parent.postMessage({
type: 'setHeight',
id: id,
height: document.documentElement.scrollHeight
}, "*");
}, 2500)
}
</script>
</body>
</html>

View File

@ -1,172 +1,72 @@
<!DOCTYPE html>
<html lang="{{ app()->getLocale() }}">
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="mobile-web-app-capable" content="yes">
<title>{{ $title ?? config('app.name', 'Pixelfed') }}</title>
<meta property="og:site_name" content="{{ config('app.name', 'pixelfed') }}">
<meta property="og:title" content="{{ $title ?? config('app.name', 'pixelfed') }}">
<meta property="og:type" content="article">
<meta property="og:url" content="{{$status->url()}}">
<meta name="medium" content="image">
<meta name="theme-color" content="#10c5f8">
<meta name="apple-mobile-web-app-capable" content="yes">
<link rel="shortcut icon" type="image/png" href="/img/favicon.png?v=2">
<link rel="apple-touch-icon" type="image/png" href="/img/favicon.png?v=2">
<link href="{{ mix('css/app.css') }}" rel="stylesheet">
<style type="text/css">
body.embed-card {
background: #fff !important;
margin: 0;
padding-bottom: 0;
}
.status-card-embed {
box-shadow: none;
border-radius: 4px;
overflow: hidden;
}
</style>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="mobile-web-app-capable" content="yes">
<title>{{ $title ?? config_cache('app.name', 'Pixelfed') }}</title>
<meta property="og:site_name" content="{{ config_cache('app.name', 'pixelfed') }}">
<meta property="og:title" content="{{ $title ?? config_cache('app.name', 'pixelfed') }}">
<meta property="og:type" content="article">
<meta property="og:url" content="{{$status['url']}}">
<meta name="medium" content="image">
<meta name="theme-color" content="#10c5f8">
<meta name="apple-mobile-web-app-capable" content="yes">
<link rel="shortcut icon" type="image/png" href="/img/favicon.png?v=2">
<link rel="apple-touch-icon" type="image/png" href="/img/favicon.png?v=2">
<style type="text/css">hr,p{margin-bottom:1rem}.small,body{font-weight:400}.card,body{display:flex}*,::after,::before{box-sizing:border-box}p{margin-top:0}a{color:#2c78bf;text-decoration:none;background-color:transparent}a:hover{color:#1e5181;text-decoration:underline}img{vertical-align:middle;border-style:none}hr{box-sizing:content-box;height:0;overflow:visible;margin-top:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small{font-size:.875em}.card{position:relative;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card-body{flex:1 1 auto;min-height:1px;padding:1.25rem}.card-footer,.card-header{padding:.75rem 1.25rem;background-color:#fff}.card-header{margin-bottom:0;border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-footer{border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.bg-white{background-color:#fff!important}.border{border:1px solid #dee2e6!important}.d-inline-flex{display:inline-flex!important}.justify-content-between{justify-content:space-between!important}.align-items-center{align-items:center!important}.my-0{margin-top:0!important}.mb-0,.my-0{margin-bottom:0!important}.mb-2{margin-bottom:.5rem!important}.pr-1{padding-right:.25rem!important}.pl-2{padding-left:.5rem!important}.text-uppercase{text-transform:uppercase!important}.font-weight-bold{font-weight:700!important}a.text-dark:focus,a.text-dark:hover{color:#000!important}a.text-muted:focus,a.text-muted:hover{color:#454b50!important}.text-muted{color:#6c757d!important}@media print{*,::after,::before{text-shadow:none!important;box-shadow:none!important}a:not(.btn){text-decoration:underline}img{page-break-inside:avoid}p{orphans:3;widows:3}body{min-width:992px!important}}body{margin:0;font-size:.9rem;line-height:1.6;color:#212529;text-align:left;background-color:rgba(247,251,253,.4705882353);min-height:100vh;flex-flow:column;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif}.text-dark{color:#212529!important}@media (max-width:576px){.card-md-rounded-0{border-width:1px 0;border-radius:0!important}}.card{box-shadow:0 2px 6px 0 hsla(0,0%,0%,.2);border:none}.status-card-embed{box-shadow:none;border-radius:4px;overflow:hidden}body.embed-card{background:#fff!important;margin:0;padding-bottom:0}.avatar{border-radius:100%}</style>
</head>
<body class="bg-white">
<div class="embed-card">
@php($item = $status)
<div class="card status-card-embed card-md-rounded-0 border">
<div class="card-header d-inline-flex align-items-center bg-white">
<img src="{{$item->profile->avatarUrl()}}" width="32px" height="32px" style="border-radius: 32px;">
<a class="username font-weight-bold pl-2 text-dark" target="_blank" href="{{$item->profile->url()}}">
{{$item->profile->username}}
</a>
</div>
<a href="{{$status->url()}}" target="_blank">
@php($status = $item)
@switch($status->viewType())
@case('photo')
@case('image')
@if($status->is_nsfw)
<details class="details-animated">
<summary>
<p class="mb-0 lead font-weight-bold">CW / NSFW / Hidden Media</p>
<p class="font-weight-light">(click to show)</p>
</summary>
<a class="max-hide-overflow {{$status->firstMedia()->filter_class}}" href="{{$status->url()}}" target="_blank">
<img class="card-img-top" src="{{$status->mediaUrl()}}">
</a>
</details>
@else
<div class="{{$status->firstMedia()->filter_class}}">
<img src="{{$status->mediaUrl()}}" width="100%">
</div>
@endif
@break
@case('photo:album')
<div id="photo-carousel-wrapper-{{$status->id}}" class="carousel slide carousel-fade mb-n3 " data-ride="carousel">
<ol class="carousel-indicators">
@for($i = 0; $i < $status->media_count; $i++)
<li data-target="#photo-carousel-wrapper-{{$status->id}}" data-slide-to="{{$i}}" class="{{$i == 0 ? 'active' : ''}}"></li>
@endfor
</ol>
<div class="carousel-inner">
@foreach($status->media()->orderBy('order')->get() as $media)
<div class="carousel-item {{$loop->iteration == 1 ? 'active' : ''}}">
<figure class="{{$media->filter_class}}">
<div class="float-right mr-3 badge badge-dark border border-secondary rounded-pill p-2" style="position:absolute;top:8px;right:0;margin-bottom:-20px;">{{$loop->iteration}}/{{$loop->count}}</div>
<img class="d-block w-100" src="{{$media->url()}}" alt="{{$status->caption}}">
</figure>
</div>
@endforeach
</div>
<a class="carousel-control-prev" href="#photo-carousel-wrapper-{{$status->id}}" role="button" data-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="carousel-control-next" href="#photo-carousel-wrapper-{{$status->id}}" role="button" data-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>
@break
@case('video')
@if($status->is_nsfw)
<details class="details-animated">
<summary>
<p class="mb-0 lead font-weight-bold">CW / NSFW / Hidden Media</p>
<p class="font-weight-light">(click to show)</p>
</summary>
<div class="embed-responsive embed-responsive-16by9">
<video class="video" preload="none" controls loop>
<source src="{{$status->firstMedia()->url()}}" type="{{$status->firstMedia()->mime}}">
</video>
</div>
</details>
@else
<div class="embed-responsive embed-responsive-16by9">
<video class="video" preload="none" controls loop>
<source src="{{$status->firstMedia()->url()}}" type="{{$status->firstMedia()->mime}}">
</video>
</div>
@endif
@break
@case('video-album')
@if($status->is_nsfw)
<details class="details-animated">
<summary>
<p class="mb-0 lead font-weight-bold">CW / NSFW / Hidden Media</p>
<p class="font-weight-light">(click to show)</p>
</summary>
<div class="embed-responsive embed-responsive-16by9">
<video class="video" preload="none" controls loop>
<source src="{{$status->firstMedia()->url()}}" type="{{$status->firstMedia()->mime}}">
</video>
</div>
</details>
@else
<div class="embed-responsive embed-responsive-16by9">
<video class="video" preload="none" controls loop>
<source src="{{$status->firstMedia()->url()}}" type="{{$status->firstMedia()->mime}}">
</video>
</div>
@endif
@break
@endswitch
</a>
@if($layout != 'compact')
<div class="card-body">
<div class="view-more mb-2">
<a class="font-weight-bold" href="{{$status->url()}}" target="_blank">View More on Pixelfed</a>
</div>
<hr>
<div class="caption">
<p class="my-0">
<span class="username font-weight-bold">
<bdi><a class="text-dark" href="{{$item->profile->url()}}" target="_blank">{{$item->profile->username}}</a></bdi>
</span>
@if($showCaption)
<span class="caption-container">{!! $item->rendered ?? e($item->caption) !!}</span>
@endif
</p>
</div>
</div>
@endif
<div class="card-footer bg-white d-inline-flex justify-content-between align-items-center">
<div class="timestamp">
<p class="small text-uppercase mb-0"><a href="{{$item->url()}}" class="text-muted" target="_blank">{{$item->created_at->diffForHumans()}}</a></p>
</div>
<div>
<a class="small font-weight-bold text-muted pr-1" href="{{config('app.url')}}" target="_blank">{{config('pixelfed.domain.app')}}</a>
<img src="/img/pixelfed-icon-color.svg" width="26px">
</div>
</div>
</div>
</div>
<script type="text/javascript">window.addEventListener("message",e=>{const t=e.data||{};window.parent&&"setHeight"===t.type&&window.parent.postMessage({type:"setHeight",id:t.id,height:document.getElementsByTagName("html")[0].scrollHeight},"*")});</script>
<script type="text/javascript">document.querySelectorAll('.caption-container a').forEach(function(i) {i.setAttribute('target', '_blank');});</script>
<script type="text/javascript" src="{{ mix('js/manifest.js') }}"></script>
<script type="text/javascript" src="{{ mix('js/vendor.js') }}"></script>
<script type="text/javascript" src="{{ mix('js/app.js') }}"></script>
<div class="embed-card">
<div class="card status-card-embed card-md-rounded-0 border">
<div class="card-header d-inline-flex align-items-center bg-white">
<img src="{{$status['account']['avatar']}}" width="32" height="32" class="avatar" onerror="this.onerror=null;this.src='/storage/avatars/default.jpg';">
<a class="username font-weight-bold pl-2 text-dark" target="_blank" rel="ugc" href="{{$status['account']['url']}}">
{{$status['account']['username']}}
</a>
</div>
<a href="{{$status['url']}}" target="_blank" rel="ugc">
<div>
<img src="{{$status['media_attachments'][0]['preview_url'] ?? $status['media_attachments'][0]['url']}}" width="100%">
</div>
</a>
@if($layout != 'compact')
<div class="card-body">
<div class="view-more mb-2">
<a class="font-weight-bold" href="{{$status['url']}}" target="_blank">View More on Pixelfed</a>
</div>
<hr>
<div class="caption">
<p class="my-0">
<span class="username font-weight-bold">
<bdi><a class="text-dark" href="{{$status['account']['url']}}" target="_blank">{{$status['account']['username']}}</a></bdi>
</span>
@if($showCaption)
<span class="caption-container">{{ $status['content_text'] }}</span>
@endif
</p>
</div>
</div>
@endif
<div class="card-footer bg-white d-inline-flex justify-content-between align-items-center">
<div class="timestamp">
<p class="small text-uppercase mb-0">
<a href="{{$status['url']}}" class="text-muted" target="_blank" rel="ugc">
{{now()->parse($status['created_at'])->diffForHumans()}}
</a>
</p>
</div>
<div>
<a class="small font-weight-bold text-muted pr-1" href="{{config('app.url')}}" target="_blank">{{config('pixelfed.domain.app')}}</a>
<img src="/img/pixelfed-icon-color.svg" width="26" height="26" />
</div>
</div>
</div>
</div>
<script type="text/javascript">
window.addEventListener("message",e=>{const t=e.data||{};window.parent&&"setHeight"===t.type&&window.parent.postMessage({type:"setHeight",id:t.id,height:document.getElementsByTagName("html")[0].scrollHeight},"*")});
document.querySelectorAll('.caption-container a').forEach(function(i) {i.setAttribute('target', '_blank');});
</script>
</body>
</html>

54
webpack.mix.js vendored
View File

@ -1,8 +1,10 @@
let mix = require('laravel-mix');
const fs = require("fs");
const path = require("path");
mix.before(() => {
fs.rmSync('public/js', { recursive: true, force: true });
fs.rmSync('public/css', { recursive: true, force: true });
fs.rmSync('public/js', { recursive: true, force: true });
});
@ -46,31 +48,35 @@ mix.version();
const TerserPlugin = require('terser-webpack-plugin');
mix.options({
processCssUrls: false,
terser: {
parallel: true,
terserOptions: {
compress: true,
output: {
comments: false
}
}
}
processCssUrls: false,
terser: {
parallel: true,
terserOptions: {
compress: true,
output: {
comments: false
}
}
}
})
mix.alias({
'@': path.join(__dirname, 'resources/assets/components'),
'~': path.join(__dirname, 'resources/assets/js/components'),
});
mix.webpackConfig({
optimization: {
providedExports: false,
sideEffects: false,
usedExports: false,
minimize: true,
minimizer: [ new TerserPlugin({
extractComments: false,
})]
},
output: {
chunkFilename: 'js/[name].[chunkhash].js',
}
optimization: {
providedExports: false,
sideEffects: false,
usedExports: false,
minimize: true,
minimizer: [ new TerserPlugin({
extractComments: false,
})]
},
output: {
chunkFilename: 'js/[name].[chunkhash].js',
}
});
mix.autoload({
jquery: ['$', 'jQuery', 'window.jQuery']
jquery: ['$', 'jQuery', 'window.jQuery']
});