pixelfed/app/Services/StoryService.php

163 lines
4.2 KiB
PHP

<?php
namespace App\Services;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Storage;
use App\Story;
use App\StoryView;
class StoryService
{
const STORY_KEY = 'pf:services:stories:v1:';
public static function get($id)
{
$account = AccountService::get($id);
if(!$account) {
return false;
}
$res = [
'profile' => [
'id' => (string) $account['id'],
'avatar' => $account['avatar'],
'username' => $account['username'],
'url' => $account['url']
]
];
$res['stories'] = self::getStories($id);
return $res;
}
public static function getById($id)
{
return Cache::remember(self::STORY_KEY . 'by-id:id-' . $id, 3600, function() use ($id) {
return Story::find($id);
});
}
public static function delById($id)
{
return Cache::forget(self::STORY_KEY . 'by-id:id-' . $id);
}
public static function getStories($id, $pid = null)
{
return Story::whereProfileId($id)
->latest()
->get()
->map(function($s) use($pid) {
return [
'id' => (string) $s->id,
'type' => $s->type,
'duration' => 10,
'seen' => in_array($pid, self::views($s->id)),
'created_at' => $s->created_at->toAtomString(),
'expires_at' => $s->expires_at->toAtomString(),
'media' => url(Storage::url($s->path)),
'can_reply' => (bool) $s->can_reply,
'can_react' => (bool) $s->can_react,
'poll' => $s->type == 'poll' ? PollService::storyPoll($s->id) : null
];
})
->toArray();
}
public static function views($id)
{
return StoryView::whereStoryId($id)
->pluck('profile_id')
->toArray();
}
public static function hasSeen($pid, $sid)
{
$key = self::STORY_KEY . 'seen:' . $pid . ':' . $sid;
return Cache::remember($key, 3600, function() use($pid, $sid) {
return StoryView::whereStoryId($sid)
->whereProfileId($pid)
->exists();
});
}
public static function latest($pid)
{
return Cache::remember(self::STORY_KEY . 'latest:pid-' . $pid, 3600, function() use ($pid) {
return Story::whereProfileId($pid)
->latest()
->first()
->id;
});
}
public static function delLatest($pid)
{
Cache::forget(self::STORY_KEY . 'latest:pid-' . $pid);
return Cache::forget('pf:stories:recent-self:' . $pid);
}
public static function addSeen($pid, $sid)
{
return Cache::put(self::STORY_KEY . 'seen:' . $pid . ':' . $sid, true, 86400);
}
public static function adminStats()
{
return Cache::remember('pf:admin:stories:stats', 300, function() {
$total = Story::count();
return [
'active' => [
'today' => Story::whereDate('created_at', now()->today())->count(),
'month' => Story::whereMonth('created_at', now()->month)->whereYear('created_at', now()->year)->count()
],
'total' => $total,
'remote' => [
'today' => Story::whereLocal(false)->whereDate('created_at', now()->today())->count(),
'month' => Story::whereLocal(false)->whereMonth('created_at', now()->month)->whereYear('created_at', now()->year)->count()
],
'storage' => [
'sum' => (int) Story::sum('size'),
'average' => (int) Story::avg('size')
],
'avg_spu' => $total ? (int) ($total / Story::groupBy('profile_id')->pluck('profile_id')->count()) : 'N/A',
'avg_duration' => (int) floor(Story::avg('duration')),
'avg_type' => $total ? Story::selectRaw('type, count(id) as count')->groupBy('type')->orderByDesc('count')->first()->type : 'N/A'
];
});
}
public static function rotateQueue()
{
return Redis::smembers('pf:stories:rotate-queue');
}
public static function addRotateQueue($id)
{
return Redis::sadd('pf:stories:rotate-queue', $id);
}
public static function removeRotateQueue($id)
{
self::delById($id);
return Redis::srem('pf:stories:rotate-queue', $id);
}
public static function reactIncrement($storyId, $profileId)
{
$key = 'pf:stories:react-counter:storyid-' . $storyId . ':profileid-' . $profileId;
if(Redis::get($key) == null) {
Redis::setex($key, 86400, 1);
} else {
return Redis::incr($key);
}
}
public static function reactCounter($storyId, $profileId)
{
$key = 'pf:stories:react-counter:storyid-' . $storyId . ':profileid-' . $profileId;
return (int) Redis::get($key) ?? 0;
}
}