mirror of
https://github.com/YGGverse/YGGtracker.git
synced 2025-02-03 02:24:25 +00:00
implement torrent posters feature #18
This commit is contained in:
parent
8ae1b3f0b7
commit
bd5191e894
6
.env
6
.env
@ -77,6 +77,9 @@ APP_APPROVED=0
|
||||
# Default Yggdrasil filters status for new users
|
||||
APP_YGGDRASIL=1
|
||||
|
||||
# Default posters status for new users
|
||||
APP_POSTERS=1
|
||||
|
||||
# Build-in trackers append to downloads
|
||||
APP_TRACKERS=http://[201:23b4:991a:634d:8359:4521:5576:15b7]:2023/announce|http://[200:1e2f:e608:eb3a:2bf:1e62:87ba:e2f7]/announce|http://[316:c51a:62a3:8b9::5]/announce
|
||||
|
||||
@ -86,6 +89,9 @@ APP_CRAWLERS=201:23b4:991a:634d:8359:4521:5576:15b7|30a:5fad::e
|
||||
# Max torrent filesize for uploads
|
||||
APP_TORRENT_FILE_SIZE_MAX=1024000
|
||||
|
||||
# Max torrent poster filesize for uploads
|
||||
APP_TORRENT_POSTER_FILE_SIZE_MAX=10240000
|
||||
|
||||
# Store wanted torrent files in /app/var/ftp by /app/crontab/torrent/scrape/{key}
|
||||
APP_TORRENT_WANTED_FTP_ENABLED=1
|
||||
APP_TORRENT_WANTED_FTP_FOLDER=/yggtracker
|
||||
|
@ -17,7 +17,9 @@ parameters:
|
||||
app.sensitive: '%env(APP_SENSITIVE)%'
|
||||
app.approved: '%env(APP_APPROVED)%'
|
||||
app.yggdrasil: '%env(APP_YGGDRASIL)%'
|
||||
app.posters: '%env(APP_POSTERS)%'
|
||||
app.torrent.size.max: '%env(APP_TORRENT_FILE_SIZE_MAX)%'
|
||||
app.torrent.poster.size.max: '%env(APP_TORRENT_POSTER_FILE_SIZE_MAX)%'
|
||||
app.torrent.wanted.ftp.enabled: '%env(APP_TORRENT_WANTED_FTP_ENABLED)%'
|
||||
app.torrent.wanted.ftp.folder: '%env(APP_TORRENT_WANTED_FTP_FOLDER)%'
|
||||
app.torrent.wanted.ftp.approved: '%env(APP_TORRENT_WANTED_FTP_APPROVED_ONLY)%'
|
||||
|
35
migrations/Version20231029184600.php
Normal file
35
migrations/Version20231029184600.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20231029184600 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('CREATE TABLE torrent_poster (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, torrent_id INTEGER NOT NULL, user_id INTEGER NOT NULL, added INTEGER NOT NULL, approved BOOLEAN NOT NULL, md5file VARCHAR(32) NOT NULL)');
|
||||
$this->addSql('ALTER TABLE user ADD COLUMN posters BOOLEAN NOT NULL DEFAULT 1');
|
||||
$this->addSql('ALTER TABLE torrent ADD COLUMN torrent_poster_id BOOLEAN NULL');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('DROP TABLE torrent_poster');
|
||||
$this->addSql('ALTER TABLE user DROP COLUMN posters');
|
||||
$this->addSql('ALTER TABLE torrent DROP COLUMN torrent_poster_id');
|
||||
}
|
||||
}
|
@ -197,29 +197,36 @@ a.button-green:hover {
|
||||
}
|
||||
|
||||
.border-color-default {
|
||||
border: 1px #5d627d solid;
|
||||
border: 1px rgba(93, 98, 125, .6) solid;
|
||||
}
|
||||
|
||||
.border-bottom-default {
|
||||
border-bottom: 1px #5d627d solid;
|
||||
border-bottom: 1px rgba(93, 98, 125, .6) solid;
|
||||
}
|
||||
|
||||
.border-top-default {
|
||||
border-top: 1px #5d627d solid;
|
||||
border-top: 1px rgba(93, 98, 125, .6) solid;
|
||||
}
|
||||
|
||||
.border-bottom-dashed {
|
||||
border-bottom: 1px #5d627d dashed;
|
||||
border-bottom: 1px rgba(93, 98, 125, .6) dashed;
|
||||
}
|
||||
|
||||
.border-top-dashed {
|
||||
border-top: 1px #5d627d dashed;
|
||||
border-top: 1px rgba(93, 98, 125, .6) dashed;
|
||||
}
|
||||
|
||||
.border-width-2-px {
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
.background-poster {
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
background-blend-mode: soft-light;
|
||||
}
|
||||
|
||||
.background-color-night {
|
||||
background-color: #34384f;
|
||||
}
|
||||
@ -503,6 +510,10 @@ a:visited.background-color-hover-night-light:hover {
|
||||
|
||||
/* responsive rules */
|
||||
|
||||
.height-148-px {
|
||||
height: 148px;
|
||||
}
|
||||
|
||||
.width-100 {
|
||||
width: 100%;
|
||||
}
|
||||
|
@ -1463,6 +1463,7 @@ class ActivityController extends AbstractController
|
||||
$this->getParameter('app.theme'),
|
||||
$this->getParameter('app.sensitive'),
|
||||
$this->getParameter('app.yggdrasil'),
|
||||
$this->getParameter('app.posters'),
|
||||
$this->getParameter('app.approved')
|
||||
);
|
||||
|
||||
|
@ -106,6 +106,22 @@ class TorrentController extends AbstractController
|
||||
// Init page
|
||||
$page = $request->get('page') ? (int) $request->get('page') : 1;
|
||||
|
||||
// Poster
|
||||
if ($user->isPosters() && $torrent->getTorrentPosterId())
|
||||
{
|
||||
$poster = $request->getScheme() . '://' .
|
||||
$request->getHttpHost() .
|
||||
$request->getBasePath() .
|
||||
$torrentService->getImageUriByTorrentPosterId(
|
||||
$torrent->getTorrentPosterId()
|
||||
);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
$poster = false;
|
||||
}
|
||||
|
||||
// Render template
|
||||
return $this->render('default/torrent/info.html.twig',
|
||||
[
|
||||
@ -155,7 +171,7 @@ class TorrentController extends AbstractController
|
||||
)
|
||||
]
|
||||
],
|
||||
'star' =>
|
||||
'star' =>
|
||||
[
|
||||
'exist' => (bool) $torrentService->findTorrentStar(
|
||||
$torrent->getId(),
|
||||
@ -165,7 +181,8 @@ class TorrentController extends AbstractController
|
||||
$torrent->getId()
|
||||
)
|
||||
],
|
||||
'contributors' => $contributors
|
||||
'contributors' => $contributors,
|
||||
'poster' => $poster
|
||||
],
|
||||
'file' =>
|
||||
[
|
||||
@ -284,6 +301,22 @@ class TorrentController extends AbstractController
|
||||
|
||||
arsort($keywords);
|
||||
|
||||
// Poster
|
||||
if ($user->isPosters() && $torrent->getTorrentPosterId())
|
||||
{
|
||||
$poster = $request->getScheme() . '://' .
|
||||
$request->getHttpHost() .
|
||||
$request->getBasePath() .
|
||||
$torrentService->getImageUriByTorrentPosterId(
|
||||
$torrent->getTorrentPosterId()
|
||||
);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
$poster = false;
|
||||
}
|
||||
|
||||
// Push torrent
|
||||
$torrents[] =
|
||||
[
|
||||
@ -351,6 +384,7 @@ class TorrentController extends AbstractController
|
||||
$torrent->getId()
|
||||
)
|
||||
],
|
||||
'poster' => $poster
|
||||
];
|
||||
}
|
||||
|
||||
@ -447,6 +481,22 @@ class TorrentController extends AbstractController
|
||||
|
||||
arsort($keywords);
|
||||
|
||||
// Poster
|
||||
if ($user->isPosters() && $torrent->getTorrentPosterId())
|
||||
{
|
||||
$poster = $request->getScheme() . '://' .
|
||||
$request->getHttpHost() .
|
||||
$request->getBasePath() .
|
||||
$torrentService->getImageUriByTorrentPosterId(
|
||||
$torrent->getTorrentPosterId()
|
||||
);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
$poster = false;
|
||||
}
|
||||
|
||||
// Push torrent
|
||||
$torrents[] =
|
||||
[
|
||||
@ -471,15 +521,6 @@ class TorrentController extends AbstractController
|
||||
'peers' => (int) $torrent->getPeers(),
|
||||
'leechers' => (int) $torrent->getLeechers(),
|
||||
],
|
||||
'user' =>
|
||||
[
|
||||
'id' => $torrent->getUserId(),
|
||||
'identicon' => $userService->identicon(
|
||||
$userService->getUser(
|
||||
$torrent->getUserId()
|
||||
)->getAddress()
|
||||
)
|
||||
],
|
||||
'keywords' => $keywords,
|
||||
'download' =>
|
||||
[
|
||||
@ -514,6 +555,7 @@ class TorrentController extends AbstractController
|
||||
$torrent->getId()
|
||||
)
|
||||
],
|
||||
'poster' => $poster
|
||||
];
|
||||
}
|
||||
|
||||
@ -1773,6 +1815,379 @@ class TorrentController extends AbstractController
|
||||
);
|
||||
}
|
||||
|
||||
// Torrent poster
|
||||
#[Route(
|
||||
'/{_locale}/torrent/{torrentId}/edit/poster/{torrentPosterId}',
|
||||
name: 'torrent_poster_edit',
|
||||
requirements:
|
||||
[
|
||||
'_locale' => '%app.locales%',
|
||||
'torrentId' => '\d+',
|
||||
'torrentPosterId' => '\d+',
|
||||
],
|
||||
defaults:
|
||||
[
|
||||
'torrentPosterId' => null,
|
||||
],
|
||||
methods:
|
||||
[
|
||||
'GET',
|
||||
'POST'
|
||||
]
|
||||
)]
|
||||
public function editPoster(
|
||||
Request $request,
|
||||
TranslatorInterface $translator,
|
||||
UserService $userService,
|
||||
TorrentService $torrentService,
|
||||
ActivityService $activityService
|
||||
): Response
|
||||
{
|
||||
// Init user
|
||||
$user = $this->initUser(
|
||||
$request,
|
||||
$userService,
|
||||
$activityService
|
||||
);
|
||||
|
||||
if (!$user->isStatus())
|
||||
{
|
||||
// @TODO
|
||||
throw new \Exception(
|
||||
$translator->trans('Access denied')
|
||||
);
|
||||
}
|
||||
|
||||
// Init torrent
|
||||
if (!$torrent = $torrentService->getTorrent($request->get('torrentId')))
|
||||
{
|
||||
throw $this->createNotFoundException();
|
||||
}
|
||||
|
||||
// Init poster value
|
||||
if ($request->get('torrentPosterId'))
|
||||
{
|
||||
if ($torrentPoster = $torrentService->getTorrentPoster($request->get('torrentPosterId')))
|
||||
{
|
||||
$torrentPosterCurrent =
|
||||
[
|
||||
'id' => $torrentPoster->getId(),
|
||||
'userId' => $torrentPoster->getUserId(),
|
||||
'value' => 'src' // @TODO
|
||||
];
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
throw $this->createNotFoundException();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($torrentPoster = $torrentService->findLastTorrentPosterByTorrentId($torrent->getId()))
|
||||
{
|
||||
$torrentPosterCurrent =
|
||||
[
|
||||
'id' => $torrentPoster->getId(),
|
||||
'userId' => $torrentPoster->getUserId(),
|
||||
'value' => 'src' // @TODO
|
||||
];
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
$torrentPosterCurrent =
|
||||
[
|
||||
'id' => null,
|
||||
'userId' => null,
|
||||
'value' => false,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Init edition history
|
||||
$editions = [];
|
||||
foreach ($torrentService->findTorrentPosterByTorrentId($torrent->getId()) as $torrentPosterEdition)
|
||||
{
|
||||
$editions[] =
|
||||
[
|
||||
'id' => $torrentPosterEdition->getId(),
|
||||
'added' => $torrentPosterEdition->getAdded(),
|
||||
'approved' => $torrentPosterEdition->isApproved(),
|
||||
'active' => $torrentPosterEdition->getId() == $torrentPosterCurrent['id'],
|
||||
'user' =>
|
||||
[
|
||||
'id' => $torrentPosterEdition->getUserId(),
|
||||
'identicon' => $userService->identicon(
|
||||
$userService->getUser(
|
||||
$torrentPosterEdition->getUserId()
|
||||
)->getAddress()
|
||||
),
|
||||
],
|
||||
'poster' =>
|
||||
$request->getScheme() . '://' .
|
||||
$request->getHttpHost() .
|
||||
$request->getBasePath() .
|
||||
$torrentService->getImageUriByTorrentPosterId(
|
||||
$torrentPosterEdition->getId()
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
// Init form
|
||||
$form =
|
||||
[
|
||||
'poster' =>
|
||||
[
|
||||
'error' => []
|
||||
]
|
||||
];
|
||||
|
||||
// Process request
|
||||
if ($request->isMethod('post'))
|
||||
{
|
||||
if ($file = $request->files->get('poster'))
|
||||
{
|
||||
//// Validate poster file
|
||||
if (filesize($file->getPathName()) > $this->getParameter('app.torrent.poster.size.max'))
|
||||
{
|
||||
$form['poster']['error'][] = $translator->trans('Poster file out of size limit');
|
||||
}
|
||||
|
||||
//// Validate image format
|
||||
if (!@getimagesize($file->getPathName()))
|
||||
{
|
||||
$form['poster']['error'][] = $translator->trans('Image file not supported');
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
$form['poster']['error'][] = $translator->trans('Poster file required');
|
||||
}
|
||||
|
||||
// Request is valid
|
||||
if (empty($form['poster']['error']))
|
||||
{
|
||||
// Save data
|
||||
$torrentPoster = $torrentService->addTorrentPoster(
|
||||
$file->getPathName(),
|
||||
$torrent->getId(),
|
||||
$user->getId(),
|
||||
time(),
|
||||
$user->isApproved()
|
||||
);
|
||||
|
||||
// Add activity event
|
||||
/* @TODO
|
||||
$activityService->addEventTorrentPosterAdd(
|
||||
$user->getId(),
|
||||
$torrent->getId(),
|
||||
time(),
|
||||
$torrentPoster->getId()
|
||||
);
|
||||
*/
|
||||
|
||||
// Redirect to info page created
|
||||
return $this->redirectToRoute(
|
||||
'torrent_info',
|
||||
[
|
||||
'_locale' => $request->get('_locale'),
|
||||
'torrentId' => $torrent->getId()
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Render form template
|
||||
return $this->render(
|
||||
'default/torrent/edit/poster.html.twig',
|
||||
[
|
||||
'torrentId' => $torrent->getId(),
|
||||
'editions' => $editions,
|
||||
'form' => $form,
|
||||
'session' =>
|
||||
[
|
||||
'moderator' => $user->isModerator(),
|
||||
'owner' => $torrentPosterCurrent['userId'] === $user->getId(),
|
||||
]
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[Route(
|
||||
'/{_locale}/torrent/{torrentId}/approve/poster/{torrentPosterId}',
|
||||
name: 'torrent_poster_approve',
|
||||
requirements:
|
||||
[
|
||||
'_locale' => '%app.locales%',
|
||||
'torrentId' => '\d+',
|
||||
'torrentPosterId' => '\d+',
|
||||
],
|
||||
methods:
|
||||
[
|
||||
'GET'
|
||||
]
|
||||
)]
|
||||
public function approvePoster(
|
||||
Request $request,
|
||||
TranslatorInterface $translator,
|
||||
UserService $userService,
|
||||
TorrentService $torrentService,
|
||||
ActivityService $activityService
|
||||
): Response
|
||||
{
|
||||
// Init user
|
||||
$user = $this->initUser(
|
||||
$request,
|
||||
$userService,
|
||||
$activityService
|
||||
);
|
||||
|
||||
// Init torrent
|
||||
if (!$torrent = $torrentService->getTorrent($request->get('torrentId')))
|
||||
{
|
||||
throw $this->createNotFoundException();
|
||||
}
|
||||
|
||||
// Init torrent poster
|
||||
if (!$torrentPoster = $torrentService->getTorrentPoster($request->get('torrentPosterId')))
|
||||
{
|
||||
throw $this->createNotFoundException();
|
||||
}
|
||||
|
||||
// Check permissions
|
||||
if (!$user->isModerator())
|
||||
{
|
||||
// @TODO
|
||||
throw new \Exception(
|
||||
$translator->trans('Access denied')
|
||||
);
|
||||
}
|
||||
|
||||
// Add activity event
|
||||
if (!$torrentPoster->isApproved())
|
||||
{
|
||||
/* @TODO
|
||||
$activityService->addEventTorrentPosterApproveAdd(
|
||||
$user->getId(),
|
||||
$torrent->getId(),
|
||||
time(),
|
||||
$torrentPoster->getId()
|
||||
);
|
||||
*/
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
/* @TODO
|
||||
$activityService->addEventTorrentPosterApproveDelete(
|
||||
$user->getId(),
|
||||
$torrent->getId(),
|
||||
time(),
|
||||
$torrentPoster->getId()
|
||||
);
|
||||
*/
|
||||
}
|
||||
|
||||
// Update approved
|
||||
$torrentService->toggleTorrentPosterApproved(
|
||||
$torrentPoster->getId()
|
||||
);
|
||||
|
||||
// Redirect
|
||||
return $this->redirectToRoute(
|
||||
'torrent_poster_edit',
|
||||
[
|
||||
'_locale' => $request->get('_locale'),
|
||||
'torrentId' => $torrent->getId(),
|
||||
'torrentPosterId' => $torrentPoster->getId(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[Route(
|
||||
'/{_locale}/torrent/{torrentId}/delete/poster/{torrentPosterId}',
|
||||
name: 'torrent_poster_delete',
|
||||
requirements:
|
||||
[
|
||||
'_locale' => '%app.locales%',
|
||||
'torrentId' => '\d+',
|
||||
'torrentPosterId' => '\d+',
|
||||
],
|
||||
methods:
|
||||
[
|
||||
'GET'
|
||||
]
|
||||
)]
|
||||
public function deletePoster(
|
||||
Request $request,
|
||||
TranslatorInterface $translator,
|
||||
UserService $userService,
|
||||
TorrentService $torrentService,
|
||||
ActivityService $activityService
|
||||
): Response
|
||||
{
|
||||
// Init user
|
||||
$user = $this->initUser(
|
||||
$request,
|
||||
$userService,
|
||||
$activityService
|
||||
);
|
||||
|
||||
// Init torrent
|
||||
if (!$torrent = $torrentService->getTorrent($request->get('torrentId')))
|
||||
{
|
||||
throw $this->createNotFoundException();
|
||||
}
|
||||
|
||||
// Init torrent poster
|
||||
if (!$torrentPoster = $torrentService->getTorrentPoster($request->get('torrentPosterId')))
|
||||
{
|
||||
throw $this->createNotFoundException();
|
||||
}
|
||||
|
||||
// Check permissions
|
||||
if (!($user->isModerator() || $user->getId() === $torrentPoster->getUserId()))
|
||||
{
|
||||
// @TODO
|
||||
throw new \Exception(
|
||||
$translator->trans('Access denied')
|
||||
);
|
||||
}
|
||||
|
||||
// Add activity event
|
||||
/* @TODO
|
||||
$activityService->addEventTorrentPosterDelete(
|
||||
$user->getId(),
|
||||
$torrent->getId(),
|
||||
time(),
|
||||
$torrentPoster->getId()
|
||||
);
|
||||
*/
|
||||
|
||||
// Update approved
|
||||
$torrentService->deleteTorrentPoster(
|
||||
$torrentPoster->getId()
|
||||
);
|
||||
|
||||
// Redirect
|
||||
return $this->redirectToRoute(
|
||||
'torrent_poster_edit',
|
||||
[
|
||||
'_locale' => $request->get('_locale'),
|
||||
'torrentId' => $torrent->getId(),
|
||||
'torrentPosterId' => $torrentPoster->getId(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Torrent star
|
||||
#[Route(
|
||||
'/{_locale}/torrent/{torrentId}/star/toggle',
|
||||
@ -2519,6 +2934,7 @@ class TorrentController extends AbstractController
|
||||
$this->getParameter('app.theme'),
|
||||
$this->getParameter('app.sensitive'),
|
||||
$this->getParameter('app.yggdrasil'),
|
||||
$this->getParameter('app.posters'),
|
||||
$this->getParameter('app.approved')
|
||||
);
|
||||
|
||||
|
@ -117,6 +117,11 @@ class UserController extends AbstractController
|
||||
$request->get('yggdrasil') === 'true'
|
||||
);
|
||||
|
||||
// Update posters
|
||||
$user->setPosters(
|
||||
$request->get('posters') === 'true'
|
||||
);
|
||||
|
||||
// Save changes to DB
|
||||
$userService->save($user);
|
||||
|
||||
@ -137,6 +142,7 @@ class UserController extends AbstractController
|
||||
'id' => $user->getId(),
|
||||
'sensitive' => $user->isSensitive(),
|
||||
'yggdrasil' => $user->isYggdrasil(),
|
||||
'posters' => $user->isPosters(),
|
||||
'locale' => $user->getLocale(),
|
||||
'locales' => $user->getLocales(),
|
||||
'events' => $user->getEvents(),
|
||||
@ -543,6 +549,11 @@ class UserController extends AbstractController
|
||||
true
|
||||
);
|
||||
|
||||
$torrentService->setTorrentPostersApprovedByUserId(
|
||||
$userTarget->getId(),
|
||||
true
|
||||
);
|
||||
|
||||
// @TODO make event for each item
|
||||
}
|
||||
|
||||
@ -613,6 +624,7 @@ class UserController extends AbstractController
|
||||
$this->getParameter('app.theme'),
|
||||
$this->getParameter('app.sensitive'),
|
||||
$this->getParameter('app.yggdrasil'),
|
||||
$this->getParameter('app.posters'),
|
||||
$this->getParameter('app.approved')
|
||||
);
|
||||
|
||||
|
@ -51,6 +51,9 @@ class Torrent
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?int $leechers = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?int $torrentPosterId = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
@ -206,4 +209,16 @@ class Torrent
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTorrentPosterId(): ?int
|
||||
{
|
||||
return $this->torrentPosterId;
|
||||
}
|
||||
|
||||
public function setTorrentPosterId(int $torrentPosterId): static
|
||||
{
|
||||
$this->torrentPosterId = $torrentPosterId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
@ -25,9 +25,6 @@ class TorrentPoster
|
||||
#[ORM\Column]
|
||||
private ?bool $approved = null;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
private ?string $color = null;
|
||||
|
||||
#[ORM\Column(length: 32)]
|
||||
private ?string $md5file = null;
|
||||
|
||||
@ -91,18 +88,6 @@ class TorrentPoster
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getColor(): ?string
|
||||
{
|
||||
return $this->color;
|
||||
}
|
||||
|
||||
public function setColor(string $color): static
|
||||
{
|
||||
$this->color = $color;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getMd5file(): ?string
|
||||
{
|
||||
return $this->md5file;
|
||||
|
@ -47,6 +47,9 @@ class User
|
||||
#[ORM\Column]
|
||||
private ?bool $yggdrasil = null;
|
||||
|
||||
#[ORM\Column]
|
||||
private ?bool $posters = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
@ -190,4 +193,16 @@ class User
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isPosters(): ?bool
|
||||
{
|
||||
return $this->posters;
|
||||
}
|
||||
|
||||
public function setPosters(bool $posters): static
|
||||
{
|
||||
$this->posters = $posters;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ namespace App\Service;
|
||||
use App\Entity\Torrent;
|
||||
use App\Entity\TorrentLocales;
|
||||
use App\Entity\TorrentSensitive;
|
||||
use App\Entity\TorrentPoster;
|
||||
use App\Entity\TorrentStar;
|
||||
use App\Entity\TorrentDownloadFile;
|
||||
use App\Entity\TorrentDownloadMagnet;
|
||||
@ -12,6 +13,7 @@ use App\Entity\TorrentDownloadMagnet;
|
||||
use App\Repository\TorrentRepository;
|
||||
use App\Repository\TorrentLocalesRepository;
|
||||
use App\Repository\TorrentSensitiveRepository;
|
||||
use App\Repository\TorrentPosterRepository;
|
||||
use App\Repository\TorrentStarRepository;
|
||||
use App\Repository\TorrentDownloadFileRepository;
|
||||
use App\Repository\TorrentDownloadMagnetRepository;
|
||||
@ -214,10 +216,93 @@ class TorrentService
|
||||
);
|
||||
}
|
||||
|
||||
public function getImageUriByTorrentPosterId(
|
||||
int $torrentPosterId,
|
||||
int $quality = 100,
|
||||
int $width = 748,
|
||||
int $height = 0,
|
||||
float $opacity = 1,
|
||||
bool $grayscale = false,
|
||||
string $format = 'webp'
|
||||
): string
|
||||
{
|
||||
$uri = sprintf(
|
||||
'/posters/%s.%s',
|
||||
implode('/', str_split($torrentPosterId)),
|
||||
$format
|
||||
);
|
||||
|
||||
$filename = sprintf(
|
||||
'%s/public/posters/%s.%s',
|
||||
$this->kernelInterface->getProjectDir(),
|
||||
implode('/', str_split($torrentPosterId)),
|
||||
$format
|
||||
);
|
||||
|
||||
if (file_exists($filename))
|
||||
{
|
||||
return $uri;
|
||||
}
|
||||
|
||||
$path = explode('/', $filename);
|
||||
|
||||
array_pop($path);
|
||||
|
||||
@mkdir(implode('/', $path), 0755, true);
|
||||
|
||||
$image = new \Imagick();
|
||||
|
||||
$image->readImage(
|
||||
$this->getStorageFilepathByTorrentPosterId(
|
||||
$torrentPosterId
|
||||
)
|
||||
);
|
||||
|
||||
$image->setImageFormat($format);
|
||||
$image->setImageCompressionQuality($quality);
|
||||
|
||||
if ($width || $height)
|
||||
{
|
||||
$image->adaptiveResizeImage(
|
||||
$width,
|
||||
$height
|
||||
);
|
||||
}
|
||||
|
||||
if ($grayscale)
|
||||
{
|
||||
$image->setImageType(
|
||||
\Imagick::IMGTYPE_GRAYSCALE
|
||||
);
|
||||
}
|
||||
|
||||
if ($opacity)
|
||||
{
|
||||
$image->setImageOpacity(
|
||||
$opacity
|
||||
);
|
||||
}
|
||||
|
||||
$image->writeImage(
|
||||
$filename
|
||||
);
|
||||
|
||||
return $uri;
|
||||
}
|
||||
|
||||
public function getStorageFilepathByTorrentPosterId(int $torrentPosterId): string
|
||||
{
|
||||
return sprintf(
|
||||
'%s/var/posters/%s',
|
||||
$this->kernelInterface->getProjectDir(),
|
||||
implode('/', str_split($torrentPosterId))
|
||||
);
|
||||
}
|
||||
|
||||
public function getStorageFilepathByTorrentId(int $torrentId): string
|
||||
{
|
||||
return sprintf(
|
||||
'%s/var/torrents/%s.torrent',
|
||||
'%s/var/torrents/%s.torrent', // @TODO remove extension as not required in background storage
|
||||
$this->kernelInterface->getProjectDir(),
|
||||
implode('/', str_split($torrentId))
|
||||
);
|
||||
@ -932,6 +1017,209 @@ class TorrentService
|
||||
}
|
||||
}
|
||||
|
||||
// Torrent poster
|
||||
public function getTorrentPoster(
|
||||
int $torrentPosterId
|
||||
): ?TorrentPoster
|
||||
{
|
||||
return $this->entityManagerInterface
|
||||
->getRepository(TorrentPoster::class)
|
||||
->find(
|
||||
$torrentPosterId
|
||||
);
|
||||
}
|
||||
|
||||
public function findTorrentPosterByMd5File(
|
||||
string $md5file
|
||||
): ?Torrent
|
||||
{
|
||||
return $this->entityManagerInterface
|
||||
->getRepository(TorrentPoster::class)
|
||||
->findOneBy(
|
||||
[
|
||||
'md5file' => $md5file
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function findLastTorrentPosterByTorrentId(
|
||||
int $torrentId
|
||||
): ?TorrentPoster
|
||||
{
|
||||
return $this->entityManagerInterface
|
||||
->getRepository(TorrentPoster::class)
|
||||
->findOneBy(
|
||||
[
|
||||
'torrentId' => $torrentId
|
||||
],
|
||||
[
|
||||
'id' => 'DESC'
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function findTorrentPosterByTorrentId(
|
||||
int $torrentId
|
||||
): array
|
||||
{
|
||||
return $this->entityManagerInterface
|
||||
->getRepository(TorrentPoster::class)
|
||||
->findBy(
|
||||
[
|
||||
'torrentId' => $torrentId
|
||||
],
|
||||
[
|
||||
'id' => 'DESC'
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function toggleTorrentPosterApproved(
|
||||
int $torrentPosterId
|
||||
): ?TorrentPoster
|
||||
{
|
||||
$torrentPoster = $this->entityManagerInterface
|
||||
->getRepository(TorrentPoster::class)
|
||||
->find($torrentPosterId);
|
||||
|
||||
$torrentPoster->setApproved(
|
||||
!$torrentPoster->isApproved() // toggle current value
|
||||
);
|
||||
|
||||
$this->entityManagerInterface->persist($torrentPoster);
|
||||
$this->entityManagerInterface->flush();
|
||||
|
||||
$this->updateTorrentPoster(
|
||||
$torrentPoster->getTorrentId()
|
||||
);
|
||||
|
||||
return $torrentSensitive;
|
||||
}
|
||||
|
||||
public function deleteTorrentPoster(
|
||||
int $torrentPosterId
|
||||
): ?TorrentPoster
|
||||
{
|
||||
// Remove torrent file from permanent storage
|
||||
$filesystem = new Filesystem();
|
||||
$filesystem->remove(
|
||||
$this->getStorageFilepathByTorrentPosterId(
|
||||
$torrentPosterId
|
||||
)
|
||||
);
|
||||
|
||||
// Remove from DB
|
||||
$torrentPoster = $this->getTorrentPoster(
|
||||
$torrentPosterId
|
||||
);
|
||||
|
||||
$this->entityManagerInterface->remove($torrentPoster);
|
||||
$this->entityManagerInterface->flush();
|
||||
|
||||
// Update torrent
|
||||
$this->updateTorrentPoster(
|
||||
$torrentPoster->getTorrentId()
|
||||
);
|
||||
|
||||
return $torrentSensitive;
|
||||
}
|
||||
|
||||
public function addTorrentPoster(
|
||||
string $filename,
|
||||
int $torrentId,
|
||||
int $userId,
|
||||
int $added,
|
||||
bool $approved
|
||||
): ?TorrentPoster
|
||||
{
|
||||
// Add new DB record
|
||||
$torrentPoster = new TorrentPoster();
|
||||
|
||||
$torrentPoster->setTorrentId($torrentId);
|
||||
$torrentPoster->setUserId($userId);
|
||||
$torrentPoster->setAdded($added);
|
||||
$torrentPoster->setApproved($approved);
|
||||
$torrentPoster->setMd5file(
|
||||
md5_file($filename)
|
||||
);
|
||||
|
||||
$this->entityManagerInterface->persist($torrentPoster);
|
||||
$this->entityManagerInterface->flush();
|
||||
|
||||
// Save file in permanent storage
|
||||
$filesystem = new Filesystem();
|
||||
$filesystem->copy(
|
||||
$filename,
|
||||
$this->getStorageFilepathByTorrentPosterId(
|
||||
$torrentPoster->getId()
|
||||
)
|
||||
);
|
||||
|
||||
// Update torrent info
|
||||
$this->updateTorrentPoster(
|
||||
$torrentId
|
||||
);
|
||||
|
||||
return $torrentPoster;
|
||||
}
|
||||
|
||||
public function setTorrentPostersApprovedByUserId(
|
||||
int $userId,
|
||||
bool $value
|
||||
): void
|
||||
{
|
||||
foreach ($this->entityManagerInterface
|
||||
->getRepository(TorrentPoster::class)
|
||||
->findBy(
|
||||
[
|
||||
'userId' => $userId
|
||||
]) as $torrentPoster)
|
||||
{
|
||||
$torrentPoster->setApproved(
|
||||
$value
|
||||
);
|
||||
|
||||
$this->entityManagerInterface->persist($torrentPoster);
|
||||
$this->entityManagerInterface->flush();
|
||||
|
||||
$this->updateTorrentPoster(
|
||||
$torrentPoster->getTorrentId(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function updateTorrentPoster(
|
||||
int $torrentId,
|
||||
): void
|
||||
{
|
||||
if ($torrent = $this->getTorrent($torrentId))
|
||||
{
|
||||
if ($torrentPoster = $this->entityManagerInterface
|
||||
->getRepository(TorrentPoster::class)
|
||||
->findOneBy(
|
||||
[
|
||||
'torrentId' => $torrentId,
|
||||
'approved' => true,
|
||||
],
|
||||
[
|
||||
'id' => 'DESC'
|
||||
]
|
||||
))
|
||||
{
|
||||
$torrent->setTorrentPosterId(
|
||||
$torrentPoster->getId()
|
||||
);
|
||||
|
||||
$this->entityManagerInterface->persist($torrent);
|
||||
$this->entityManagerInterface->flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Torrent star
|
||||
public function findTorrentStar(
|
||||
int $torrentId,
|
||||
|
@ -32,6 +32,7 @@ class UserService
|
||||
string $theme,
|
||||
bool $sensitive = true,
|
||||
bool $yggdrasil = true,
|
||||
bool $posters = true,
|
||||
bool $approved = false,
|
||||
bool $moderator = false,
|
||||
bool $status = true
|
||||
@ -84,6 +85,10 @@ class UserService
|
||||
$yggdrasil
|
||||
);
|
||||
|
||||
$user->setPosters(
|
||||
$posters
|
||||
);
|
||||
|
||||
$this->entityManagerInterface->persist($user);
|
||||
$this->entityManagerInterface->flush();
|
||||
|
||||
|
84
templates/default/torrent/edit/poster.html.twig
Normal file
84
templates/default/torrent/edit/poster.html.twig
Normal file
@ -0,0 +1,84 @@
|
||||
{% extends 'default/layout.html.twig' %}
|
||||
{% block title %}{{ 'Edit torrent poster' | trans }} - {{ 'Torrent' | trans }} #{{ torrentId }} - {{ name }}{% endblock %}
|
||||
{% block main_content %}
|
||||
<div class="padding-24-px margin-y-8-px border-radius-3-px background-color-night">
|
||||
<div class="margin-b-24-px padding-b-16-px border-bottom-default">
|
||||
<h1>
|
||||
{{'Edit poster for torrent' | trans }}
|
||||
<a href="{{ path('torrent_info', { torrentId : torrentId }) }}">#{{ torrentId }}</a>
|
||||
</h1>
|
||||
</div>
|
||||
<form name="poster" method="post" enctype="multipart/form-data" action="{{ path('torrent_poster_edit', { torrentId : torrentId }) }}">
|
||||
<div class="margin-y-16-px">
|
||||
{% for error in form.poster.error %}
|
||||
<div class="text-color-red margin-b-8-px">
|
||||
{{ error }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
<input class="width-100" type="file" name="poster" value="" />
|
||||
</div>
|
||||
<div class="padding-t-4-px margin-b-16-px border-bottom-default"></div>
|
||||
<div class="text-right">
|
||||
<a class="margin-r-8-px" href="{{ path('torrent_info', { torrentId : torrentId }) }}">
|
||||
{{'cancel' | trans }}
|
||||
</a>
|
||||
<input class="button-green" type="submit" value="{{'Submit'|trans }}" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% for edition in editions %}
|
||||
<div class="padding-x-24-px padding-y-16-px margin-y-8-px border-radius-3-px {% if edition.active %}background-color-night-light height-148-px{% else %}background-color-night{% endif %} {% if edition.poster %}background-poster{% endif %}"
|
||||
{% if edition.poster %}style="background-image:url('{{ edition.poster }}')"{% endif %}>
|
||||
{% if edition.active %}
|
||||
{{ edition.added | format_ago }}
|
||||
{% else %}
|
||||
<a href="{{ path('torrent_poster_edit', { torrentId : torrentId, torrentPosterId : edition.id }) }}">
|
||||
{{ edition.added | format_ago }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{{ 'by' | trans }}
|
||||
<a href="{{ path('user_info', { userId : edition.user.id }) }}">
|
||||
<img class="border-radius-50 border-color-default vertical-align-middle" src="{{ edition.user.identicon }}" alt="{{'identicon'|trans }}" />
|
||||
</a>
|
||||
<div class="float-right">
|
||||
{% if session.moderator or session.owner %}
|
||||
<a class="margin-r-8-px text-color-red" href="{{ path('torrent_poster_delete', { torrentId : torrentId, torrentPosterId : edition.id }) }}" title="{{ 'Delete' | trans }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-x-circle" viewBox="0 0 16 16">
|
||||
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/>
|
||||
<path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z"/>
|
||||
</svg>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if edition.approved %}
|
||||
{% if session.moderator %}
|
||||
<a href="{{ path('torrent_poster_approve', { torrentId : torrentId, torrentPosterId : edition.id }) }}" title="{{ 'Disapprove' | trans }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-.01-1.05z"/>
|
||||
</svg>
|
||||
</a>
|
||||
{% else %}
|
||||
<span title="{{ 'Approved' | trans }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-.01-1.05z"/>
|
||||
</svg>
|
||||
</span>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if session.moderator %}
|
||||
<a href="{{ path('torrent_poster_approve', { torrentId : torrentId, torrentPosterId : edition.id }) }}" title="{{ 'Approve' | trans }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-hourglass" viewBox="0 0 16 16">
|
||||
<path d="M2 1.5a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-1v1a4.5 4.5 0 0 1-2.557 4.06c-.29.139-.443.377-.443.59v.7c0 .213.154.451.443.59A4.5 4.5 0 0 1 12.5 13v1h1a.5.5 0 0 1 0 1h-11a.5.5 0 1 1 0-1h1v-1a4.5 4.5 0 0 1 2.557-4.06c.29-.139.443-.377.443-.59v-.7c0-.213-.154-.451-.443-.59A4.5 4.5 0 0 1 3.5 3V2h-1a.5.5 0 0 1-.5-.5zm2.5.5v1a3.5 3.5 0 0 0 1.989 3.158c.533.256 1.011.791 1.011 1.491v.702c0 .7-.478 1.235-1.011 1.491A3.5 3.5 0 0 0 4.5 13v1h7v-1a3.5 3.5 0 0 0-1.989-3.158C8.978 9.586 8.5 9.052 8.5 8.351v-.702c0-.7.478-1.235 1.011-1.491A3.5 3.5 0 0 0 11.5 3V2h-7z"/>
|
||||
</svg>
|
||||
</a>
|
||||
{% else %}
|
||||
<span title="{{ 'Waiting for approve' | trans }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-hourglass" viewBox="0 0 16 16">
|
||||
<path d="M2 1.5a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-1v1a4.5 4.5 0 0 1-2.557 4.06c-.29.139-.443.377-.443.59v.7c0 .213.154.451.443.59A4.5 4.5 0 0 1 12.5 13v1h1a.5.5 0 0 1 0 1h-11a.5.5 0 1 1 0-1h1v-1a4.5 4.5 0 0 1 2.557-4.06c.29-.139.443-.377.443-.59v-.7c0-.213-.154-.451-.443-.59A4.5 4.5 0 0 1 3.5 3V2h-1a.5.5 0 0 1-.5-.5zm2.5.5v1a3.5 3.5 0 0 0 1.989 3.158c.533.256 1.011.791 1.011 1.491v.702c0 .7-.478 1.235-1.011 1.491A3.5 3.5 0 0 0 4.5 13v1h7v-1a3.5 3.5 0 0 0-1.989-3.158C8.978 9.586 8.5 9.052 8.5 8.351v-.702c0-.7.478-1.235 1.011-1.491A3.5 3.5 0 0 0 11.5 3V2h-7z"/>
|
||||
</svg>
|
||||
</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
@ -29,7 +29,8 @@
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% block main_content %}
|
||||
<div class="padding-24-px margin-y-8-px border-radius-3-px background-color-night">
|
||||
<div class="padding-24-px margin-y-8-px border-radius-3-px background-color-night {% if torrent.poster %}background-poster{% endif %}"
|
||||
{% if torrent.poster %}style="background-image:url('{{ torrent.poster }}')"{% endif %}>
|
||||
<h1 class="display-block text-center margin-b-16-px">
|
||||
{{ file.name }}
|
||||
{#{{ 'Torrent' | trans }} #{{ torrent.id }}#}
|
||||
@ -364,6 +365,22 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<a class="margin-r-4-px{#opacity-0 parent-hover-opacity-09#}" href="{{ path('torrent_poster_edit', { torrentId : torrent.id }) }}" title="{{'Edit'|trans }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" fill="currentColor" viewBox="0 0 16 16">
|
||||
<path d="M12.854.146a.5.5 0 0 0-.707 0L10.5 1.793 14.207 5.5l1.647-1.646a.5.5 0 0 0 0-.708l-3-3zm.646 6.061L9.793 2.5 3.293 9H3.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.207l6.5-6.5zm-7.468 7.468A.5.5 0 0 1 6 13.5V13h-.5a.5.5 0 0 1-.5-.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.5-.5V10h-.5a.499.499 0 0 1-.175-.032l-.179.178a.5.5 0 0 0-.11.168l-2 5a.5.5 0 0 0 .65.65l5-2a.5.5 0 0 0 .168-.11l.178-.178z"/>
|
||||
</svg>
|
||||
</a>
|
||||
{{ 'Poster' | trans }}
|
||||
<div class="padding-b-8-px border-bottom-default"></div>
|
||||
<div class="padding-t-16-px text-left">
|
||||
{% if torrent.poster %}
|
||||
{{ 'Yes' | trans }}
|
||||
{% else %}
|
||||
{{ 'No' | trans }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a name="activity"></a>
|
||||
<div class="padding-t-16-px padding-b-8-px text-right">
|
||||
|
@ -24,7 +24,8 @@
|
||||
</div>
|
||||
{% if torrents %}
|
||||
{% for torrent in torrents %}
|
||||
<div class="padding-24-px margin-y-8-px border-radius-3-px background-color-night">
|
||||
<div class="padding-24-px margin-y-8-px border-radius-3-px background-color-night {% if torrent.poster %}background-poster{% endif %}"
|
||||
{% if torrent.poster %}style="background-image:url('{{ torrent.poster }}')"{% endif %}>
|
||||
<a name="{{ torrent.id }}"></a>
|
||||
<div class="margin-b-16-px">
|
||||
<h2>
|
||||
@ -86,15 +87,6 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="margin-b-16-px border-bottom-default"></div>
|
||||
{#
|
||||
<sup>
|
||||
{{ torrent.added | format_ago }}
|
||||
{{ 'by' | trans }}
|
||||
<a href="{{ path('user_info', { userId : torrent.user.id }) }}">
|
||||
<img class="border-radius-50 border-color-default vertical-align-middle margin-x-4-px" src="{{ torrent.user.identicon }}" alt="{{ 'identicon' | trans }}" />
|
||||
</a>
|
||||
</sup>
|
||||
#}
|
||||
<span class="margin-r-4-px cursor-default" title="{{ 'Size' | trans }}">
|
||||
<small>
|
||||
{{ torrent.file.size | format_bytes }}
|
||||
|
@ -58,6 +58,23 @@
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="padding-y-12-px">
|
||||
{{ 'Posters' | trans }}
|
||||
</td>
|
||||
<td class="padding-y-12-px">
|
||||
<div class="margin-r-8-px">
|
||||
{% if user.posters %}
|
||||
<input name="posters" id="posters" type="checkbox" value="true" checked="checked" />
|
||||
{% else %}
|
||||
<input name="posters" id="posters" type="checkbox" value="true" />
|
||||
{% endif %}
|
||||
<label class="margin-x-4-px" for="posters">
|
||||
{{ 'Enabled' | trans }}
|
||||
</label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="padding-b-8-px border-bottom-default text-right" colspan="2">
|
||||
{{ 'Search' | trans }}
|
||||
|
Loading…
x
Reference in New Issue
Block a user