Commit c219a3d5 authored by SeeBeyond's avatar SeeBeyond

Merge branch 'difficultyrating-songfilters' into 'master'

Difficultyrating songfilters

See merge request !2
parents 0a06774a fb0084e8
......@@ -364,6 +364,11 @@ input[type="range"]::-ms-fill-lower {
grid-template-columns: repeat(6, 1fr);
grid-gap: 15px;
}
.song-row .song-list-5 {
display: grid;
grid-template-columns: repeat(5, 1fr);
grid-gap: 15px;
}
.song-row .pagination {
text-align: right;
margin-top: 25px;
......@@ -470,14 +475,10 @@ input[type="range"]::-ms-fill-lower {
padding: 3px 8px;
margin-right: 4px;
font-size: 10px;
opacity: 0.3;
}
.song-item .song-metadata .song-difficulties .difficulty span {
font-weight: bold;
}
.song-item .song-metadata .song-difficulties .difficulty.active {
opacity: 1;
}
.song-item:not(.inactive):hover {
cursor: pointer;
background: rgba(255, 255, 255, 0.2);
......@@ -630,4 +631,3 @@ input[type="range"]::-ms-fill-lower {
grid-template-columns: repeat(6, 1fr);
}
}
/*# sourceMappingURL=main.css.map */
\ No newline at end of file
......@@ -379,6 +379,11 @@ input[type="range"]::-ms-fill-lower {
grid-template-columns: repeat(6, 1fr);
grid-gap: 15px;
}
& .song-list-5 {
display: grid;
grid-template-columns: repeat(5, 1fr);
grid-gap: 15px;
}
& .pagination {
text-align: right;
margin-top: 25px;
......@@ -494,16 +499,11 @@ input[type="range"]::-ms-fill-lower {
padding: 3px 8px;
margin-right: 4px;
font-size: 10px;
opacity: 0.3;
& span {
// padding-right: 3px;
font-weight: bold;
}
&.active {
opacity: 1;
}
}
}
}
......
.section-search {
display: grid;
grid-template-rows: auto 1fr;
grid-gap: 25px;
min-height: 100vh;
grid-template-rows: 1fr;
grid-template-columns: 350px 1fr;
grid-template-areas: "filters results";
}
.section-search header {
background: rgba(0, 0, 0, 0.5);
padding: 50px;
padding-bottom: 25px;
.section-search .search-filters {
grid-area: filters;
background: #101314;
padding: 30px;
}
.section-search header .title {
font-size: 32px;
letter-spacing: 0.05em;
.section-search .search-filters header {
font-size: 14px;
letter-spacing: 0.25em;
font-weight: bold;
text-transform: uppercase;
margin-bottom: 15px;
font-family: 'Oswald', sans-serif;
}
.section-search header .actions {
.section-search .search-filters .filter-input {
margin-bottom: 25px;
}
.section-search .search-filters .filter-input .filter-difficulty {
position: relative;
display: grid;
grid-template-columns: 1fr auto;
grid-gap: 15px;
grid-template-columns: auto 1fr;
grid-gap: 10px;
margin-top: 10px;
cursor: pointer;
align-items: center;
overflow: hidden;
}
.section-search .search-filters .filter-input .filter-difficulty input {
position: absolute;
top: 0px;
left: 0px;
bottom: 0px;
right: 0px;
visibility: hidden;
}
.section-search .search-filters .filter-input .filter-difficulty input:checked + span {
background: rgba(123, 228, 163, 0.3);
}
.section-search .search-filters .filter-input .filter-difficulty input:checked + span::before {
transform: translateX(20px);
background: #7be4a3;
}
.section-search .search-filters .filter-input .filter-difficulty span {
height: 20px;
width: 40px;
background: rgba(255, 255, 255, 0.2);
border-radius: 100px;
transition: 0.2s ease-in-out all;
}
.section-search header .actions .show-all {
height: 100%;
display: flex;
justify-content: center;
.section-search .search-filters .filter-input .filter-difficulty span::before {
transition: 0.2s ease-in-out all;
content: "";
display: block;
height: 20px;
width: 20px;
border-radius: 100px;
background: #fff;
}
.section-search .search-filters .filter-input .filter-difficulty div {
display: block;
position: relative;
}
.section-search .search-filters .filter-input .filter-rating {
position: relative;
display: grid;
grid-template-columns: auto 1fr;
grid-gap: 10px;
margin-top: 10px;
cursor: pointer;
align-items: center;
padding: 0px 10px;
}
.section-search header .actions input {
width: 100%;
.section-search .search-filters .filter-input .filter-rating div {
display: block;
position: relative;
}
.section-search .search-filters .filter-input .filter-rating input[type="number"] {
width: 75px;
font-family: 'Open Sans', sans-serif;
font-size: 14px;
background: transparent;
color: #fff;
border-radius: 4px;
padding: 9px 20px;
......@@ -40,22 +88,54 @@
border: 0px;
transition: 0.2s ease-in-out all;
}
.section-search header .actions input:hover {
.section-search .search-filters .filter-input .filter-rating input[type="number"]:hover {
background: rgba(255, 255, 255, 0.3);
color: #fff;
}
.section-search header .actions input:focus {
.section-search .search-filters .filter-input .filter-rating input[type="number"]:focus {
outline: 0;
background: rgba(255, 255, 255, 0.3);
}
.section-search header .actions input::placeholder {
color: rgba(255, 255, 255, 0.6);
.section-search .search-filters .filter-input .filter-rating input[type="number"]::placeholder {
color: rgba(255, 255, 255, 0.5);
}
.section-search .search-filters input[type="submit"] {
font-family: 'Open Sans', sans-serif;
text-decoration: none;
border: 0px;
color: #fff;
font-size: 12px;
font-weight: bold;
letter-spacing: 0.1em;
background: linear-gradient(135deg, rgba(255, 255, 255, 0.3), rgba(255, 255, 255, 0.1));
padding: 10px 20px;
border-radius: 4px;
text-transform: uppercase;
transition: 0.2s ease-in-out all;
cursor: pointer;
}
.section-search .search-filters input[type="submit"]:hover {
opacity: 0.6;
text-decoration: none;
}
.section-search .search-filters input[type="submit"]:focus {
outline: 0;
}
.section-search .search-filters input[type="submit"]:disabled,
.section-search .search-filters input[type="submit"].button-disabled {
opacity: 0.4;
cursor: not-allowed;
}
.section-search .search-filters input[type="submit"].button-icon {
padding: 5px 15px;
font-size: 18px;
}
.section-search .search-results {
display: grid;
grid-area: results;
grid-template-rows: auto auto auto 1fr;
grid-gap: 25px;
padding: 0px 50px;
padding: 30px;
}
.section-search .search-results .search-results-users {
display: grid;
......
.section-search {
display: grid;
grid-template-rows: auto 1fr;
grid-gap: 25px;
min-height: 100vh;
grid-template-rows: 1fr;
grid-template-columns: 350px 1fr;
grid-template-areas: "filters results";
& header {
background: rgba(0,0,0,0.5);
padding: 50px;
padding-bottom: 25px;
& .search-filters {
grid-area: filters;
background: #101314;
padding: 30px;
& .title {
font-size: 32px;
letter-spacing: 0.05em;
& header {
font-size: 14px;
letter-spacing: 0.25em;
font-weight: bold;
text-transform: uppercase;
margin-bottom: 15px;
font-family: 'Oswald', sans-serif;
}
& .actions {
display: grid;
grid-template-columns: 1fr auto;
grid-gap: 15px;
align-items: center;
& .show-all {
height: 100%;
display: flex;
justify-content: center;
& .filter-input {
margin-bottom: 25px;
& .filter-difficulty {
position: relative;
display: grid;
grid-template-columns: auto 1fr;
grid-gap: 10px;
margin-top: 10px;
cursor: pointer;
align-items: center;
padding: 0px 10px;
}
overflow: hidden;
input {
width: 100%;
font-family: 'Open Sans', sans-serif;
font-size: 14px;
background: transparent;
color: #fff;
border-radius: 4px;
padding: 9px 20px;
background: rgba(255,255,255,0.15);
border: 0px;
transition: 0.2s ease-in-out all;
&:hover {
background: rgba(255,255,255,0.3);
color: #fff;
& input {
position: absolute;
top: 0px;
left: 0px;
bottom: 0px;
right: 0px;
visibility: hidden;
&:checked + span {
background: rgba(123, 228, 163, 0.3);
}
&:checked + span::before {
transform: translateX(20px);
background: rgb(123, 228, 163);
}
}
&:focus {
outline: 0;
background: rgba(255,255,255,0.3);
& span {
height: 20px;
width: 40px;
background: rgba(255,255,255,0.2);
border-radius: 100px;
transition: 0.2s ease-in-out all;
&::before {
transition: 0.2s ease-in-out all;
content: "";
display: block;
height: 20px;
width: 20px;
border-radius: 100px;
background: #fff;
}
}
& div {
display: block;
position: relative;
}
}
& .filter-rating {
position: relative;
display: grid;
grid-template-columns: auto 1fr;
grid-gap: 10px;
margin-top: 10px;
cursor: pointer;
align-items: center;
& div {
display: block;
position: relative;
}
&::placeholder {
color: rgba(255,255,255,0.6);
& input[type="number"] {
width: 75px;
font-family: 'Open Sans', sans-serif;
font-size: 14px;
color: #fff;
border-radius: 4px;
padding: 9px 20px;
background: rgba(255,255,255,0.15);
border: 0px;
transition: 0.2s ease-in-out all;
&:hover {
background: rgba(255,255,255,0.3);
color: #fff;
}
&:focus {
outline: 0;
background: rgba(255,255,255,0.3);
}
&::placeholder {
color: rgba(255,255,255,0.5);
}
}
}
}
& input[type="submit"] {
font-family: 'Open Sans', sans-serif;
font-size: 12px;
text-decoration: none;
border: 0px;
color: #fff;
font-size: 12px;
font-weight: bold;
letter-spacing: 0.1em;
background: linear-gradient(135deg, rgba(255,255,255,0.3), rgba(255,255,255,0.1));
padding: 10px 20px;
border-radius: 4px;
text-transform: uppercase;
transition: 0.2s ease-in-out all;
cursor: pointer;
&:hover {
opacity: 0.6;
text-decoration: none;
}
&:focus {
outline: 0;
}
&:disabled, &.button-disabled {
opacity: 0.4;
cursor: not-allowed;
}
&.button-icon {
padding: 5px 15px;
font-size: 18px;
}
}
}
& .search-results {
display: grid;
grid-area: results;
grid-template-rows: auto auto auto 1fr;
grid-gap: 25px;
padding: 0px 50px;
padding: 30px;
& .search-results-users {
display: grid;
......
......@@ -125,14 +125,19 @@
}
.section-song-detail .song-detail .song-statistics .stat .difficulties {
align-self: center;
height: 20px;
display: flex;
}
.section-song-detail .song-detail .song-statistics .stat .difficulties img {
height: 25px;
margin-right: 5px;
opacity: 0.4;
.section-song-detail .song-detail .song-statistics .stat .difficulties .difficulty {
background: #fff;
color: #000;
border-radius: 4px;
padding: 3px 8px;
margin-right: 4px;
font-size: 10px;
}
.section-song-detail .song-detail .song-statistics .stat .difficulties img.active {
opacity: 1;
.section-song-detail .song-detail .song-statistics .stat .difficulties .difficulty span {
font-weight: bold;
}
.section-song-detail .song-detail .song-statistics .stat .content {
align-self: center;
......@@ -687,4 +692,3 @@
grid-template-columns: 1fr;
}
}
/*# sourceMappingURL=songdetail.css.map */
\ No newline at end of file
......@@ -143,14 +143,20 @@
& .difficulties {
align-self: center;
& img {
height: 25px;
margin-right: 5px;
opacity: 0.4;
&.active {
opacity: 1;
height: 20px;
display: flex;
& .difficulty {
background: #fff;
color: #000;
border-radius: 4px;
padding: 3px 8px;
margin-right: 4px;
font-size: 10px;
& span {
// padding-right: 3px;
font-weight: bold;
}
}
}
......
......@@ -47,20 +47,54 @@ class IndexController extends AbstractController
}
/**
* @Route("/hot", name="index.hot")
* @Route("/updated", name="index.updated")
*/
public function hot(Request $request)
public function updated(Request $request)
{
$em = $this->getDoctrine()->getManager();
$data = [];
$hotOffset = $request->query->get('hotOffset') ? $request->query->get('hotOffset') : 0;
$resultsHotSongs = $em->getRepository(Song::class)->getHot($hotOffset);
$updatedOffset = $request->query->get('updatedOffset') ? $request->query->get('updatedOffset') : 0;
$resultsUpdatedSongs = $em->getRepository(Song::class)->getUpdated($updatedOffset);
$data['hotSongs'] = $resultsHotSongs;
$data['hotOffset'] = $hotOffset;
$data['updatedSongs'] = $resultsUpdatedSongs;
$data['updatedOffset'] = $updatedOffset;
return $this->render('index/hot.html.twig', $data);
return $this->render('index/updated.html.twig', $data);
}
/**
* @Route("/hotThisWeek", name="index.hotThisWeek")
*/
public function hotThisWeek(Request $request)
{
$em = $this->getDoctrine()->getManager();
$data = [];
$hotWeekOffset = $request->query->get('hotWeekOffset') ? $request->query->get('hotWeekOffset') : 0;
$resultsHotWeekSongs = $em->getRepository(Song::class)->getHotThisWeek($hotWeekOffset);
$data['hotWeekSongs'] = $resultsHotWeekSongs;
$data['hotWeekOffset'] = $hotWeekOffset;
return $this->render('index/hotThisWeek.html.twig', $data);
}
/**
* @Route("/hotThisMonth", name="index.hotThisMonth")
*/
public function hotThisMonth(Request $request)
{
$em = $this->getDoctrine()->getManager();
$data = [];
$hotMonthOffset = $request->query->get('hotMonthOffset') ? $request->query->get('hotMonthOffset') : 0;
$resultsHotMonthSongs = $em->getRepository(Song::class)->getHotThisMonth($hotMonthOffset);
$data['hotMonthSongs'] = $resultsHotMonthSongs;
$data['hotMonthOffset'] = $hotMonthOffset;
return $this->render('index/hotThisMonth.html.twig', $data);
}
/**
......
......@@ -83,7 +83,7 @@ class ClientReleasesController extends AbstractController
$em->persist($newRelease);
$em->flush();
return $this->redirectToRoute('moderation.index');
return $this->redirectToRoute('moderation.clientreleases.index');
} catch(FileException $e) {
}
......@@ -118,6 +118,6 @@ class ClientReleasesController extends AbstractController
$em->remove($releaseToRemove);
$em->flush();
return $this->redirectToRoute('moderation.index');
return $this->redirectToRoute('moderation.clientreleases.index');
}
}
......@@ -127,8 +127,163 @@ class SystemController extends AbstractController
exit;
}
exit;
return $this->redirectToRoute('moderation.system.index');
}
/**
* @Route("/moderation/system/migration/difficultyRating/{songID}", name="moderation.system.migration.difficultyRating")
*/
public function systemMigrationDifficultyRating(Request $request, int $songID = 1)
{
$em = $this->getDoctrine()->getManager();
$baseUrl = $request->getScheme() . '://' . $request->getHttpHost() . $request->getBasePath();
// Calculate Max Count
$songCount = $em->getRepository(Song::class)->createQueryBuilder('u')->select('count(u.id)')->getQuery()->getSingleScalarResult();
if($songID > $songCount) {
return $this->redirectToRoute('moderation.system.index');
}
// Find Song
$songToProcess = $em->getRepository(Song::class)->findOneBy(array('id' => $songID));
// Go To Next if not found
if($songToProcess == null) {
return $this->render('moderation/migration/difficultyRating.html.twig', array('songID' => $songID + 1));
}
// Calculate MD5 Hash
try {
// Load SRTB file
$srtbPath = glob($this->getParameter('srtb_path').DIRECTORY_SEPARATOR.$songToProcess->getFileReference().".srtb");
$srtbContent = json_decode(file_get_contents($srtbPath[0]));
$trackInfo = null;
$clipInfo = [];
$trackData = [];
foreach($srtbContent->largeStringValuesContainer->values as $valueItem) {
if(strpos($valueItem->key, "TrackInfo") !== false) {
$trackInfo = json_decode($valueItem->val);
}
if(strpos($valueItem->key, "ClipInfo") !== false) {
$i = str_replace("SO_ClipInfo_ClipInfo_", "", $valueItem->key);
$clipInfo[$i] = json_decode($valueItem->val);
}
if(strpos($valueItem->key, "TrackData") !== false) {
$i = str_replace("SO_TrackData_TrackData_", "", $valueItem->key);
$trackData[$i] = json_decode($valueItem->val);
}
}
// Reset Values
$songToProcess->setHasEasyDifficulty(false);
$songToProcess->setHasNormalDifficulty(false);
$songToProcess->setHasHardDifficulty(false);
$songToProcess->setHasExtremeDifficulty(false);
$songToProcess->setHasXDDifficulty(false);
// Detect used difficulties
foreach($trackInfo->difficulties as $oneData) {
if(isset($oneData->_active) && $oneData->_active || !isset($oneData->_active)) {
switch($oneData->_difficulty) {
case 2:
$songToProcess->setHasEasyDifficulty(true);
break;
case 3:
$songToProcess->setHasNormalDifficulty(true);
break;
case 4:
$songToProcess->setHasHardDifficulty(true);
break;
case 5:
$songToProcess->setHasExtremeDifficulty(true);
break;
case 6:
$songToProcess->setHasXDDifficulty(true);
break;
}
}
}
// Reset difficulty ratings
$songToProcess->setEasyDifficulty(false);
$songToProcess->setNormalDifficulty(false);
$songToProcess->setHardDifficulty(false);
$songToProcess->setExpertDifficulty(false);
$songToProcess->setXDDifficulty(false);
// Detect difficulty ratings
foreach($trackData as $trackDataItem) {
switch($trackDataItem->difficultyType) {
case 2:
$songToProcess->setEasyDifficulty($trackDataItem->difficultyRating);
break;
case 3:
$songToProcess->setNormalDifficulty($trackDataItem->difficultyRating);
break;
case 4:
$songToProcess->setHardDifficulty($trackDataItem->difficultyRating);
break;
case 5:
$songToProcess->setExpertDifficulty($trackDataItem->difficultyRating);
break;
case 6:
$songToProcess->setXDDifficulty($trackDataItem->difficultyRating);
break;
}
}
$em->persist($songToProcess);
$em->flush();
// Go To Next
return $this->render('moderation/migration/difficultyRating.html.twig', array('songID' => $songID + 1));
} catch(\Exception $e) {
var_dump($e);
exit;
}
}
/**
* @Route("/moderation/system/migration/updateHash/{songID}", name="moderation.system.migration.updateHash")
*/
public function systemMigrationUpdateHash(Request $request, int $songID = 1)
{
$em = $this->getDoctrine()->getManager();
$baseUrl = $request->getScheme() . '://' . $request->getHttpHost() . $request->getBasePath();
// Calculate Max Count
$songCount = $em->getRepository(Song::class)->createQueryBuilder('u')->select('count(u.id)')->getQuery()->getSingleScalarResult();
if($songID > $songCount) {
return $this->redirectToRoute('moderation.system.index');
}
// Find Song
$songToProcess = $em->getRepository(Song::class)->findOneBy(array('id' => $songID));
// Go To Next if not found
if($songToProcess == null) {
return $this->render('moderation/migration/updateHash.html.twig', array('songID' => $songID + 1));
}
// Calculate MD5 Hash
try {
// Load SRTB file
$srtbPath = glob($this->getParameter('srtb_path').DIRECTORY_SEPARATOR.$songToProcess->getFileReference().".srtb");
$srtbContentRaw = file_get_contents($srtbPath[0]);
// Save MD5 Hash
$songToProcess->setUpdateHash(md5($srtbContentRaw));
$em->persist($songToProcess);
$em->flush();
// Go To Next
return $this->render('moderation/migration/updateHash.html.twig', array('songID' => $songID + 1));
} catch(\Exception $e) {
var_dump($e);
exit;
}
}
}
......@@ -30,6 +30,15 @@ class SearchController extends AbstractController
$data['results']['users'] = $resultsUsers;
$data['results']['songs'] = $resultsSongs;
$filterEasy = true;
$filterNormal = true;
$filterHard = true;
$filterExpert = true;
$filterXD = true;
$filterMinDifficulty = 0;
$filterMaxDifficulty = 99;
} else {
if($searchQuery != null) {
$resultsUsers = $em->getRepository(User::class)->createQueryBuilder('o')
......@@ -39,24 +48,78 @@ class SearchController extends AbstractController
->getQuery()
->getResult();
$resultsSongs = $em->getRepository(Song::class)->createQueryBuilder('o')
->where('o.title LIKE :query')
->orWhere('o.subtitle LIKE :query')
->orWhere('o.tags LIKE :query')
->orWhere('o.artist LIKE :query')
->orWhere('o.charter LIKE :query')
->andWhere('o.publicationStatus IN (0, 1)')
->orderBy('o.id', 'DESC')
->setParameter('query', '%'.$searchQuery.'%')
->getQuery()
->getResult();
$resultsSongs = $em->getRepository(Song::class)->createQueryBuilder('o');
$resultsSongs->where('o.title LIKE :query');
$resultsSongs->orWhere('o.subtitle LIKE :query');
$resultsSongs->orWhere('o.tags LIKE :query');
$resultsSongs->orWhere('o.artist LIKE :query');
$resultsSongs->orWhere('o.charter LIKE :query');
// Add Filters for difficulty
$filterEasy = $request->query->get('diffEasy') == 'on' ? true : false;
$filterNormal = $request->query->get('diffNormal') == 'on' ? true : false;
$filterHard = $request->query->get('diffHard') == 'on' ? true : false;
$filterExpert = $request->query->get('diffExpert') == 'on' ? true : false;
$filterXD = $request->query->get('diffXD') == 'on' ? true : false;
// Add Filters for difficulty ratings
$filterMinDifficulty = intval($request->query->get('diffRatingFrom'));
$filterMaxDifficulty = intval($request->query->get('diffRatingTo'));
if($filterMinDifficulty == null) { $filterMinDifficulty = 0; }
if($filterMaxDifficulty == null) { $filterMaxDifficulty = 99; }
$resultsSongs->setParameter('query', "%".$searchQuery."%");
$resultsSongs->andWhere('o.publicationStatus IN (0, 1)');
$resultsSongs->orderBy('o.id', 'DESC');
$resultsSongs = $resultsSongs->getQuery()->getResult();
// Filter Song Results
$filteredResultsSongs = [];
foreach($resultsSongs as $resultSong) {
// Has the required difficulty
if($filterEasy && $resultSong->getHasEasyDifficulty() ||
$filterNormal && $resultSong->getHasNormalDifficulty() ||
$filterHard && $resultSong->getHasHardDifficulty() ||
$filterExpert && $resultSong->getHasExtremeDifficulty() ||
$filterXD && $resultSong->getHasXDDifficulty()) {
// Has the minimum difficulty rating
if($resultSong->getHasEasyDifficulty() && $resultSong->getEasyDifficulty() >= $filterMinDifficulty ||
$resultSong->getHasNormalDifficulty() && $resultSong->getNormalDifficulty() >= $filterMinDifficulty ||
$resultSong->getHasHardDifficulty() && $resultSong->getHardDifficulty() >= $filterMinDifficulty ||
$resultSong->getHasExtremeDifficulty() && $resultSong->getExpertDifficulty() >= $filterMinDifficulty ||
$resultSong->getHasXDDifficulty() && $resultSong->getXDDifficulty() >= $filterMinDifficulty) {
// Has the maximum difficulty rating
if($resultSong->getHasEasyDifficulty() && $resultSong->getEasyDifficulty() <= $filterMaxDifficulty ||
$resultSong->getHasNormalDifficulty() && $resultSong->getNormalDifficulty() <= $filterMaxDifficulty ||
$resultSong->getHasHardDifficulty() && $resultSong->getHardDifficulty() <= $filterMaxDifficulty ||
$resultSong->getHasExtremeDifficulty() && $resultSong->getExpertDifficulty() <= $filterMaxDifficulty ||
$resultSong->getHasXDDifficulty() && $resultSong->getXDDifficulty() <= $filterMaxDifficulty) {
$filteredResultsSongs[] = $resultSong;
}
}
}
}
$data['results']['users'] = $resultsUsers;
$data['results']['songs'] = $resultsSongs;
$data['results']['songs'] = $filteredResultsSongs;
}
}
$data['searchQuery'] = $searchQuery;
$data['filterEasy'] = $filterEasy;
$data['filterNormal'] = $filterNormal;
$data['filterHard'] = $filterHard;
$data['filterExpert'] = $filterExpert;
$data['filterXD'] = $filterXD;
$data['diffRatingFrom'] = $filterMinDifficulty;
$data['diffRatingTo'] = $filterMaxDifficulty;
return $this->render('search/index.html.twig', $data);
}
......
......@@ -231,6 +231,7 @@ class SongController extends AbstractController
$song->setTags($data['tags']);
$song->setDescription($data['description']);
$song->setIsExplicit($data['isExplicit']);
$song->setUpdateDate(new \DateTime('NOW'));
$song->setPublicationStatus($data['publicationStatus']);
if($backupFile) {
......@@ -305,12 +306,23 @@ class SongController extends AbstractController
$song->setArtist($trackInfo->artistName);
$song->setCharter($trackInfo->charter);
// Generate new UpdateHash
$song->setUpdateHash(md5(json_encode($srtbContent)));
// Reset Difficulty Ratings
$song->setHasEasyDifficulty(false);
$song->setHasNormalDifficulty(false);
$song->setHasHardDifficulty(false);
$song->setHasExtremeDifficulty(false);
$song->setHasXDDifficulty(false);
$song->setEasyDifficulty(null);
$song->setNormalDifficulty(null);
$song->setHardDifficulty(null);
$song->setExpertDifficulty(null);
$song->setXDDifficulty(null);
// Detect difficulties
foreach($trackInfo->difficulties as $oneData) {
if(isset($oneData->_active) && $oneData->_active || !isset($oneData->_active)) {
switch($oneData->_difficulty) {
......@@ -332,6 +344,27 @@ class SongController extends AbstractController
}
}
}
// Detect difficulty ratings
foreach($trackData as $trackDataItem) {
switch($trackDataItem->difficultyType) {
case 2:
$song->setEasyDifficulty($trackDataItem->difficultyRating);
break;
case 3:
$song->setNormalDifficulty($trackDataItem->difficultyRating);
break;
case 4:
$song->setHardDifficulty($trackDataItem->difficultyRating);
break;
case 5:
$song->setExpertDifficulty($trackDataItem->difficultyRating);
break;
case 6:
$song->setXDDifficulty($trackDataItem->difficultyRating);
break;
}
}
} catch(Exception $e) {
var_dump($e);
......
......@@ -101,6 +101,9 @@ class UploadController extends AbstractController
$song->setHasExtremeDifficulty(false);
$song->setHasXDDifficulty(false);
$song->setUpdateHash(md5(json_encode($srtbContent)));
// Detect used difficulties
foreach($trackInfo->difficulties as $oneData) {
if(isset($oneData->_active) && $oneData->_active || !isset($oneData->_active)) {
switch($oneData->_difficulty) {
......@@ -122,7 +125,31 @@ class UploadController extends AbstractController
}
}
}
// Detect difficulty ratings
foreach($trackData as $trackDataItem) {
switch($trackDataItem->difficultyType) {
case 2:
$song->setEasyDifficulty($trackDataItem->difficultyRating);
break;
case 3:
$song->setNormalDifficulty($trackDataItem->difficultyRating);
break;
case 4:
$song->setHardDifficulty($trackDataItem->difficultyRating);
break;
case 5:
$song->setExpertDifficulty($trackDataItem->difficultyRating);
break;
case 6:
$song->setXDDifficulty($trackDataItem->difficultyRating);
break;
}
}
} catch(Exception $e) {
var_dump($e);
exit;
$this->addFlash('error', 'Uploading failed. Please report back to our development team!');
// clean up temp files
......
......@@ -99,11 +99,41 @@ class Song
*/
private $hasXDDifficulty;
/**
* @ORM\Column(type="integer", nullable=true, options={"default": 0})
*/
private $easyDifficulty;
/**
* @ORM\Column(type="integer", nullable=true, options={"default": 0})
*/
private $normalDifficulty;
/**
* @ORM\Column(type="integer", nullable=true, options={"default": 0})
*/
private $hardDifficulty;
/**
* @ORM\Column(type="integer", nullable=true, options={"default": 0})
*/
private $expertDifficulty;
/**
* @ORM\Column(type="integer", nullable=true, options={"default": 0})
*/
private $XDDifficulty;
/**
* @ORM\Column(type="datetime")
*/
private $uploadDate;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $updateHash;
/**
* @ORM\Column(type="text", nullable=true)
*/
......@@ -124,6 +154,11 @@ class Song
*/
private $songPlaylists;
/**
* @ORM\Column(type="datetime", nullable=true)
*/
private $updateDate;
public function __construct()
{
$this->reviews = new ArrayCollection();
......@@ -333,6 +368,86 @@ class Song
return $this;
}
public function getEasyDifficulty(): ?int
{
return $this->easyDifficulty;
}
public function setEasyDifficulty(?int $easyDifficulty): self
{
if($easyDifficulty != null) {
$this->easyDifficulty = max(0, min(99, $easyDifficulty));
} else {
$this->easyDifficulty = $easyDifficulty;
}
return $this;
}
public function getNormalDifficulty(): ?int
{
return $this->normalDifficulty;
}
public function setNormalDifficulty(?int $normalDifficulty): self
{
if($normalDifficulty != null) {
$this->normalDifficulty = max(0, min(99, $normalDifficulty));
} else {
$this->normalDifficulty = $normalDifficulty;
}
return $this;
}
public function getHardDifficulty(): ?int
{
return $this->hardDifficulty;
}
public function setHardDifficulty(?int $hardDifficulty): self
{
if($hardDifficulty != null) {
$this->hardDifficulty = max(0, min(99, $hardDifficulty));
} else {
$this->hardDifficulty = $hardDifficulty;
}
return $this;
}
public function getExpertDifficulty(): ?int
{
return $this->expertDifficulty;
}
public function setExpertDifficulty(?int $expertDifficulty): self
{
if($expertDifficulty != null) {
$this->expertDifficulty = max(0, min(99, $expertDifficulty));
} else {
$this->expertDifficulty = $expertDifficulty;
}
return $this;
}
public function getXDDifficulty(): ?int
{
return $this->XDDifficulty;
}
public function setXDDifficulty(?int $XDDifficulty): self
{
if($XDDifficulty != null) {
$this->XDDifficulty = max(0, min(99, $XDDifficulty));
} else {
$this->XDDifficulty = $XDDifficulty;
}
return $this;
}
public function getUploadDate(): ?DateTimeInterface
{
return $this->uploadDate;
......@@ -345,6 +460,18 @@ class Song
return $this;
}
public function getUpdateHash(): ?string
{
return $this->updateHash;
}
public function setUpdateHash(?string $updateHash): self
{
$this->updateHash = $updateHash;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
......@@ -438,7 +565,14 @@ class Song
'hasHardDifficulty' => $this->hasHardDifficulty,
'hasExtremeDifficulty' => $this->hasExtremeDifficulty,
'hasXDDifficulty' => $this->hasXDDifficulty,
'easyDifficulty' => $this->easyDifficulty,
'normalDifficulty' => $this->normalDifficulty,
'hardDifficulty' => $this->hardDifficulty,
'expertDifficulty' => $this->expertDifficulty,
'XDDifficulty' => $this->XDDifficulty,
'uploadDate' => $this->uploadDate,
'updateDate' => $this->updateDate,
'updateHash' => $this->updateHash,
'description' => $this->description
);
}
......@@ -470,4 +604,16 @@ class Song
return $this;
}
public function getUpdateDate(): ?\DateTimeInterface
{
return $this->updateDate;
}
public function setUpdateDate(?\DateTimeInterface $updateDate): self
{
$this->updateDate = $updateDate;
return $this;
}
}
......@@ -42,7 +42,7 @@
private $reviews;
/**
* @ORM\ManyToMany(targetEntity="App\Entity\SongSpinPlay", mappedBy="user")
* @ORM\OneToMany(targetEntity="App\Entity\SongSpinPlay", mappedBy="user")
*/
private $spinPlays;
......
......@@ -24,12 +24,23 @@ class SongRepository extends ServiceEntityRepository
$qb
->where('e.publicationStatus = 0')
->orderBy('e.uploadDate', 'DESC')
->setFirstResult(12 * $page)
->setMaxResults(12);
->setFirstResult(10 * $page)
->setMaxResults(10);
return $qb->getQuery()->getResult();
}
public function getHot(int $page) {
public function getUpdated(int $page) {
$qb = $this->createQueryBuilder("e");
$qb
->where('e.publicationStatus = 0')
->orderBy('e.updateDate', 'DESC')
->addOrderBy('e.uploadDate', 'DESC')
->setFirstResult(10 * $page)
->setMaxResults(10);
return $qb->getQuery()->getResult();
}
public function getHotThisWeek(int $page) {
$qb = $this->createQueryBuilder("e");
$qb
->where('e.publicationStatus = 0')
......@@ -37,13 +48,28 @@ class SongRepository extends ServiceEntityRepository
->andWhere('e.uploadDate >= :end')
->orderBy('e.downloads', 'DESC')
->addOrderBy('e.views', 'DESC')
->setFirstResult(12 * $page)
->setMaxResults(12)
->setFirstResult(10 * $page)
->setMaxResults(10)
->setParameter('begin', new \DateTime('NOW'))
->setParameter('end', new \DateTime('-7 days'));
return $qb->getQuery()->getResult();
}
public function getHotThisMonth(int $page) {
$qb = $this->createQueryBuilder("e");
$qb
->where('e.publicationStatus = 0')
->andWhere('e.uploadDate <= :begin')
->andWhere('e.uploadDate >= :end')
->orderBy('e.downloads', 'DESC')
->addOrderBy('e.views', 'DESC')
->setFirstResult(10 * $page)
->setMaxResults(10)
->setParameter('begin', new \DateTime('NOW'))
->setParameter('end', new \DateTime('-1 month'));
return $qb->getQuery()->getResult();
}
public function getPopular(int $page) {
return [];
}
......
......@@ -26,29 +26,34 @@
<div class="alert alert-primary" role="alert">
<h4 class="alert-heading">Last Update</h4>
This documentation was last updated on 11/28/2020 at 15:05 CEST
This documentation was last updated on 01/22/2021 at 14:58 CEST
</div>
<div class="card">
<h2 class="card-title">11/28/2020</h2>
<h2 class="card-title">01/22/2021</h2>
<ul>
<li>Deprecated the Open Discovery->Popular endpoint</li>
<li>Added a link to the main website</li>
<li>Removed the Open Discovery->Popular endpoint</li>
<li>Added difficulty ratings to songs</li>
<li>Added an update hash and update time to songs</li>
<li>Renamed Discovery->Hot endpoint to Discovery->HotThisWeek</li>
<li>Added Discovery->HotThisMonth endpoint</li>
<li>Added Discovery->Updated endpoint</li>
<li>Limited the Discovery endpoint outputs to 10 per page (was 12 before)</li>
</ul>
</div>
<div class="card">
<h2 class="card-title">11/02/2020</h2>
<h2 class="card-title">11/28/2020</h2>
<ul>
<li>Added preferred pronouns for user profiles</li>
<li>Deprecated the Open Discovery->Popular endpoint</li>
<li>Added a link to the main website</li>
</ul>
</div>
<div class="card">
<h2 class="card-title">10/14/2020</h2>
<h2 class="card-title">11/02/2020</h2>
<ul>
<li>Updated Tournament output</li>
<lI>Added Playlists</lI>
<li>Added preferred pronouns for user profiles</li>
</ul>
</div>
</div>
......
......@@ -25,7 +25,14 @@
</tr>
<tr>
<th>JSON Body</th>
<td>(string) searchQuery</td>
<td>(string) searchQuery<br />
(bool) diffEasy<br />
(bool) diffNormal<br />
(bool) diffHard<br />
(bool) diffExpert<br />
(bool) diffXD<br />
(int) diffRatingFrom<br />
(int) diffRatingTo</td>
</tr>
</table>
......@@ -60,6 +67,12 @@
"hasHardDifficulty":false,
"hasExtremeDifficulty":false,
"hasXDDifficulty":true,
"easyDifficulty": 5,
"normalDifficulty": 10,
"hardDifficulty": 15,
"expertDifficulty": 23,
"XDDifficulty": 26,
"updateHash": "d837d2adcdc19d215130cd92f27ae927",
"cover":"https:\/\/spinsha.re\/uploads\/thumbnail\/spinshare_5f2d157f6e44a.jpg",
"zip":"https:\/\/spinsha.re\/api\/song\/1024\/download"
},
......@@ -128,7 +141,7 @@
<div class="card" id="new">
<h2 class="card-title">New Songs</h2>
<p>Returns the 12 newest songs. Use <code class="code">offset</code> for pagination.</p>
<p>Returns the 10 newest songs. Use <code class="code">offset</code> for pagination.</p>
<table class="table table-bordered">
<tr>
......@@ -160,6 +173,12 @@
"hasHardDifficulty": true,
"hasExtremeDifficulty": false,
"hasXDDifficulty": false,
"easyDifficulty": 5,
"normalDifficulty": 10,
"hardDifficulty": 15,
"expertDifficulty": 23,
"XDDifficulty": 26,
"updateHash": "d837d2adcdc19d215130cd92f27ae927",
"cover":"https:\/\/spinsha.re\/uploads\/thumbnail\/spinshare_5e8df6fb90bd7.jpg",
"zip":"https:\/\/spinsha.re\/api\/song\/3\/download"
},
......@@ -180,9 +199,69 @@
</pre>
</div>
<div class="card" id="hot">
<h2 class="card-title">Hot Songs</h2>
<p>Returns the 12 most popular songs from the last 7 days. Use <code class="code">offset</code> for pagination.</p>
<div class="card" id="updated">
<h2 class="card-title">Updated Songs</h2>
<p>Returns 10 songs that were last updated. Use <code class="code">offset</code> for pagination.</p>
<table class="table table-bordered">
<tr>
<th>Method</th>
<td>GET</td>
</tr>
<tr>
<th>Endpoint</th>
<td>/songs/updated/<code class="code">offset</code></td>
</tr>
</table>
<br /><br />
<strong>Output Body (Success)</strong>
<pre class="code">
{
"version":1,
"status":200,
"data":[
{
"id": 3,
"title": "Isabelle Singing",
"subtitle": "K.K. Bubblegum",
"artist": "K.K. Slider",
"charter": "Ellite",
"hasEasyDifficulty": false,
"hasNormalDifficulty": false,
"hasHardDifficulty": true,
"hasExtremeDifficulty": false,
"hasXDDifficulty": false,
"easyDifficulty": 5,
"normalDifficulty": 10,
"hardDifficulty": 15,
"expertDifficulty": 23,
"XDDifficulty": 26,
"updateHash": "d837d2adcdc19d215130cd92f27ae927",
"cover":"https:\/\/spinsha.re\/uploads\/thumbnail\/spinshare_5e8df6fb90bd7.jpg",
"zip":"https:\/\/spinsha.re\/api\/song\/3\/download"
},
...
]
}
</pre>
<br />
<strong>Output Body (Not Found)</strong>
<pre class="code">
{
"version":1,
"status":404,
"data":[]
}
</pre>
</div>
<div class="card" id="hotThisWeek">
<h2 class="card-title">Hot This Week Songs</h2>
<p>Returns the 10 most popular songs from the last 7 days. Use <code class="code">offset</code> for pagination.</p>
<table class="table table-bordered">
<tr>
......@@ -214,6 +293,12 @@
"hasHardDifficulty": true,
"hasExtremeDifficulty": false,
"hasXDDifficulty": false,
"easyDifficulty": 5,
"normalDifficulty": 10,
"hardDifficulty": 15,
"expertDifficulty": 23,
"XDDifficulty": 26,
"updateHash": "d837d2adcdc19d215130cd92f27ae927",
"cover":"https:\/\/spinsha.re\/uploads\/thumbnail\/spinshare_5e8df6fb90bd7.jpg",
"zip":"https:\/\/spinsha.re\/api\/song\/3\/download"
},
......@@ -234,9 +319,9 @@
</pre>
</div>
<div class="card" id="popular">
<h2 class="card-title">Popular Songs <span class="badge badge-secondary">deprecated</span></h2>
<p>Returns the 12 most popular songs of all time. Use <code class="code">offset</code> for pagination.</p>
<div class="card" id="hotThisMonth">
<h2 class="card-title">Hot This Month Songs</h2>
<p>Returns the 10 most popular songs from the last month. Use <code class="code">offset</code> for pagination.</p>
<table class="table table-bordered">
<tr>
......@@ -245,16 +330,55 @@
</tr>
<tr>
<th>Endpoint</th>
<td>/songs/popular/<code class="code">offset</code></td>
<td>/songs/hotThisMonth/<code class="code">offset</code></td>
</tr>
</table>
<br /><br />
<strong>Output Body (Success)</strong>
<pre class="code">
{
"version":1,
"status":200,
"data":[
{
"id": 3,
"title": "Isabelle Singing",
"subtitle": "K.K. Bubblegum",
"artist": "K.K. Slider",
"charter": "Ellite",
"hasEasyDifficulty": false,
"hasNormalDifficulty": false,
"hasHardDifficulty": true,
"hasExtremeDifficulty": false,
"hasXDDifficulty": false,
"easyDifficulty": 5,
"normalDifficulty": 10,
"hardDifficulty": 15,
"expertDifficulty": 23,
"XDDifficulty": 26,
"updateHash": "d837d2adcdc19d215130cd92f27ae927",
"cover":"https:\/\/spinsha.re\/uploads\/thumbnail\/spinshare_5e8df6fb90bd7.jpg",
"zip":"https:\/\/spinsha.re\/api\/song\/3\/download"
},
...
]
}
</pre>
<br />
<div class="alert alert-secondary" role="alert">
<h4 class="alert-heading">Deprecated</h4>
This API-Endpoint was deprecated and should not be used anymore.
</div>
<strong>Output Body (Not Found)</strong>
<pre class="code">
{
"version":1,
"status":404,
"data":[]
}
</pre>
</div>
</div>
</div>
<div class="col-lg-3">
......@@ -264,8 +388,9 @@
<a href="#search">Search</a>
<a href="#searchAll">Search All</a>
<a href="#new">New Songs</a>
<a href="#hot">Hot Songs</a>
<a href="#popular">Popular Songs <span class="badge badge-secondary">Deprecated</span></a>
<a href="#updated">Updated Songs</a>
<a href="#hotThisWeek">Hot This Week Songs</a>
<a href="#hotThisMonth">Hot This Month Songs</a>
</div>
</div>
</div>
......
......@@ -72,11 +72,24 @@
"hasHardDifficulty": false,
"hasExtremeDifficulty": false,
"hasXDDifficulty": true,
"uploadDate": {
"date": "2020-10-14 12:50:25.000000",
"timezone_type": 3,
"timezone": "Europe\/Berlin"
"easyDifficulty": 5,
"normalDifficulty": 10,
"hardDifficulty": 15,
"expertDifficulty": 23,
"XDDifficulty": 26,
"uploadDate":
{
"date": "2021-01-15 13:27:34.000000",
"timezone_type": 3,
"timezone": "Europe/Berlin"
},
"updateDate":
{
"date": "2021-01-15 13:27:34.000000",
"timezone_type": 3,
"timezone": "Europe/Berlin"
},
"updateHash": "d837d2adcdc19d215130cd92f27ae927",
"description": null
}
],
......
......@@ -37,46 +37,54 @@
<strong>Output Body</strong>
<pre class="code">
{
"version":1,
"status":200,
"data":{
"id":3,
"title":"Isabelle Singing",
"subtitle":"K.K. Bubblegum",
"artist":"K.K. Slider",
"charter":"Ellite",
"uploader":3,
"fileReference":"spinshare_5e8df6fb90bd7",
"tags":[
"isabelle",
"singing",
"easy",
"cute",
"animal",
"crossing",
"acnh",
"new",
"horizons"
"version": 1,
"status": 200,
"data":
{
"id": 10,
"title": "Shiny Days",
"subtitle": "From \"Yuru Camp\"",
"artist": "Asaka",
"charter": "imfallin",
"uploader": 1,
"fileReference": "spinshare_60018a36ec5e9",
"tags":
[
""
],
"views":774,
"downloads":98,
"isExplicit":false,
"isTournament":false,
"hasEasyDifficulty":false,
"hasNormalDifficulty":false,
"hasHardDifficulty":true,
"hasExtremeDifficulty":false,
"hasXDDifficulty":false,
"uploadDate":{
"date":"2020-05-01 00:00:00.000000",
"timezone_type":3,
"timezone":"Europe\/Berlin"
"views": 9,
"downloads": null,
"isExplicit": false,
"publicationStatus": 0,
"hasEasyDifficulty": true,
"hasNormalDifficulty": true,
"hasHardDifficulty": true,
"hasExtremeDifficulty": true,
"hasXDDifficulty": true,
"easyDifficulty": 5,
"normalDifficulty": 10,
"hardDifficulty": 15,
"expertDifficulty": 23,
"XDDifficulty": 26,
"uploadDate":
{
"date": "2021-01-15 13:27:34.000000",
"timezone_type": 3,
"timezone": "Europe/Berlin"
},
"updateDate":
{
"date": "2021-01-15 13:27:34.000000",
"timezone_type": 3,
"timezone": "Europe/Berlin"
},
"description":null,
"paths":{
"ogg":"https:\/\/spinsha.re\/uploads\/audio\/spinshare_5e8df6fb90bd7_0.ogg",
"cover":"https:\/\/spinsha.re\/uploads\/thumbnail\/spinshare_5e8df6fb90bd7.jpg",
"zip":"https:\/\/spinsha.re\/api\/song\/3\/download"
"updateHash": "d837d2adcdc19d215130cd92f27ae927",
"description": null,
"paths":
{
"ogg": "http://localhost/www/spinshare/server/public/uploads/audio/spinshare_60018a36ec5e9_0.ogg",
"cover": "http://localhost/www/spinshare/server/public/uploads/thumbnail/spinshare_60018a36ec5e9.jpg",
"zip": "http://localhost/www/spinshare/server/public/api/song/10/download"
}
}
}
......
......@@ -48,6 +48,13 @@
<form action="{{ path('search.index') }}" method="GET" class="search">
<input name="q" type="search" placeholder="Search for songs, tags & profiles..." value="{{ searchQuery|default('') }}" />
<input type="hidden" name="diffEasy" value="on" />
<input type="hidden" name="diffNormal" value="on" />
<input type="hidden" name="diffHard" value="on" />
<input type="hidden" name="diffExpert" value="on" />
<input type="hidden" name="diffXD" value="on" />
<input type="hidden" name="diffRatingFrom" value="0" />
<input type="hidden" name="diffRatingTo" value="99" />
</form>
<nav class="items-right">
......
......@@ -8,16 +8,11 @@
<div class="song-title">{{ song.title|default('Untitled') }}</div>
<div class="song-artist">{{ song.artist|default('Unknown') }}</div>
<div class="song-difficulties">
<div class="difficulty {{ song.hasEasyDifficulty ? "active" : "" }}"><span>E</span></div>
<div class="difficulty {{ song.hasNormalDifficulty ? "active" : "" }}"><span>N</span></div>
<div class="difficulty {{ song.hasHardDifficulty ? "active" : "" }}"><span>H</span></div>
<div class="difficulty {{ song.hasExtremeDifficulty ? "active" : "" }}"><span>EX</span></div>
<div class="difficulty {{ song.hasXDDifficulty ? "active" : "" }}"><span>XD</span></div>
<!-- <img src="{{ asset('assets/img/difficultyEasy.svg') }}" class="{{ song.hasEasyDifficulty ? "active" : "" }}" alt="Easy Difficulty" />
<img src="{{ asset('assets/img/difficultyNormal.svg') }}" class="{{ song.hasNormalDifficulty ? "active" : "" }}" alt="Normal Difficulty" />
<img src="{{ asset('assets/img/difficultyHard.svg') }}" class="{{ song.hasHardDifficulty ? "active" : "" }}" alt="Hard Difficulty" />
<img src="{{ asset('assets/img/difficultyExtreme.svg') }}" class="{{ song.hasExtremeDifficulty ? "active" : "" }}" alt="Extreme Difficulty" />
<img src="{{ asset('assets/img/difficultyXD.svg') }}" class="{{ song.hasXDDifficulty ? "active" : "" }}" alt="xD Difficulty" /> -->
{% if song.hasEasyDifficulty %}<div class="difficulty"><span>E</span> {{ song.easyDifficulty }}</div>{% endif %}
{% if song.hasNormalDifficulty %}<div class="difficulty"><span>N</span> {{ song.normalDifficulty }}</div>{% endif %}
{% if song.hasHardDifficulty %}<div class="difficulty"><span>H</span> {{ song.hardDifficulty }}</div>{% endif %}
{% if song.hasExtremeDifficulty %}<div class="difficulty"><span>EX</span> {{ song.expertDifficulty }}</div>{% endif %}
{% if song.hasXDDifficulty %}<div class="difficulty"><span>XD</span> {{ song.XDDifficulty }}</div>{% endif %}
</div>
</div>
</a>
\ No newline at end of file
......@@ -8,7 +8,9 @@
<div class="tabs">
<a href="{{ path('index.index') }}" class="tab {% if app.request.attributes.get('_route') == 'index.index' %}active{% endif %}">Frontpage</a>
<a href="{{ path('index.new') }}" class="tab {% if app.request.attributes.get('_route') == 'index.new' %}active{% endif %}">New</a>
<a href="{{ path('index.hot') }}" class="tab {% if app.request.attributes.get('_route') == 'index.hot' %}active{% endif %}">Hot</a>
<a href="{{ path('index.updated') }}" class="tab {% if app.request.attributes.get('_route') == 'index.updated' %}active{% endif %}">Updated</a>
<a href="{{ path('index.hotThisWeek') }}" class="tab {% if app.request.attributes.get('_route') == 'index.hotThisWeek' %}active{% endif %}">Hot This Week</a>
<a href="{{ path('index.hotThisMonth') }}" class="tab {% if app.request.attributes.get('_route') == 'index.hotThisMonth' %}active{% endif %}">Hot This Month</a>
</div>
</header>
......
{% extends 'index/base.html.twig' %}
{% block indexContent %}
<div class="song-row song-row-hot">
<div class="song-list">
{% for song in hotMonthSongs %}
{{ include('components/song-item.html.twig', {song: song}) }}
{% endfor %}
</div>
<div class="pagination">
{% if hotMonthOffset > 0 %}
<a href="{{ path('index.hot', {hotMonthOffset: hotMonthOffset - 1}) }}" class="button"><i class="mdi mdi-chevron-left"></i> PREVIOUS</a>
{% else %}
<a class="button button-disabled"><i class="mdi mdi-chevron-left"></i> PREVIOUS</a>
{% endif %}
{% if hotMonthSongs|length < 12 %}
<a class="button button-disabled">NEXT <i class="mdi mdi-chevron-right"></i></a>
{% else %}
<a href="{{ path('index.hot', {hotMonthOffset: hotMonthOffset + 1}) }}" class="button">NEXT <i class="mdi mdi-chevron-right"></i></a>
{% endif %}
</div>
</div>
{% endblock %}
\ No newline at end of file
......@@ -3,20 +3,20 @@
{% block indexContent %}
<div class="song-row song-row-hot">
<div class="song-list">
{% for song in hotSongs %}
{% for song in hotWeekSongs %}
{{ include('components/song-item.html.twig', {song: song}) }}
{% endfor %}
</div>
<div class="pagination">
{% if hotOffset > 0 %}
<a href="{{ path('index.hot', {hotOffset: hotOffset - 1}) }}" class="button"><i class="mdi mdi-chevron-left"></i> PREVIOUS</a>
{% if hotWeekOffset > 0 %}
<a href="{{ path('index.hot', {hotWeekOffset: hotWeekOffset - 1}) }}" class="button"><i class="mdi mdi-chevron-left"></i> PREVIOUS</a>
{% else %}
<a class="button button-disabled"><i class="mdi mdi-chevron-left"></i> PREVIOUS</a>
{% endif %}
{% if hotSongs|length < 12 %}
{% if hotWeekSongs|length < 12 %}
<a class="button button-disabled">NEXT <i class="mdi mdi-chevron-right"></i></a>
{% else %}
<a href="{{ path('index.hot', {hotOffset: hotOffset + 1}) }}" class="button">NEXT <i class="mdi mdi-chevron-right"></i></a>
<a href="{{ path('index.hot', {hotWeekOffset: hotWeekOffset + 1}) }}" class="button">NEXT <i class="mdi mdi-chevron-right"></i></a>
{% endif %}
</div>
</div>
......
......@@ -82,7 +82,7 @@
</div>
<div class="support-subsection">
<h1>Our Patreons</h1>
<h1>Our Patrons</h1>
<div class="user-list">
{% for user in patreons %}
<a href="{{ path('user.detail', {userId: user.id}) }}" class="user-item">
......
{% extends 'index/base.html.twig' %}
{% block indexContent %}
<div class="song-row song-row-new">
<div class="song-list">
{% for song in updatedSongs %}
{{ include('components/song-item.html.twig', {song: song}) }}
{% endfor %}
</div>
<div class="pagination">
{% if updatedOffset > 0 %}
<a href="{{ path('index.new', {updatedOffset: updatedOffset - 1}) }}" class="button"><i class="mdi mdi-chevron-left"></i> PREVIOUS</a>
{% else %}
<a class="button button-disabled"><i class="mdi mdi-chevron-left"></i> PREVIOUS</a>
{% endif %}
{% if updatedSongs|length < 12 %}
<a class="button button-disabled">NEXT <i class="mdi mdi-chevron-right"></i></a>
{% else %}
<a href="{{ path('index.new', {updatedOffset: updatedOffset + 1}) }}" class="button">NEXT <i class="mdi mdi-chevron-right"></i></a>
{% endif %}
</div>
</div>
{% endblock %}
\ No newline at end of file
<meta http-equiv="refresh" content="1; URL={{ path('moderation.system.migration.difficultyRating', {songID: songID}) }}">
Processing...<br />
(Next Song ID: {{ songID }})
\ No newline at end of file
<meta http-equiv="refresh" content="1; URL={{ path('moderation.system.migration.updateHash', {songID: songID}) }}">
Processing...<br />
(Next Song ID: {{ songID }})
\ No newline at end of file
......@@ -17,8 +17,11 @@
<div class="box">
Generate On All Songs Actions<br /><strong>(ATTENTION: They can take a while!)</strong><br /><br />
<a href="{{ path('moderation.system.generate.thumbnails') }}" class="button">Generate Thumbnails</a> <a href="{{ path('moderation.system.generate.thumbnails-missing') }}" class="button">Generate Missing Thumbnails</a><br /><br />
<a href="{{ path('moderation.system.cleanup.temp') }}" class="button">Cleanup Temp Folder</a>
<a href="{{ path('moderation.system.generate.thumbnails') }}" class="button">Generate Thumbnails</a><br /><br />
<a href="{{ path('moderation.system.generate.thumbnails-missing') }}" class="button">Generate Missing Thumbnails</a><br /><br />
<a href="{{ path('moderation.system.cleanup.temp') }}" class="button">Cleanup Temp Folder</a><br /><br />
<a href="{{ path('moderation.system.migration.updateHash') }}" class="button">Regenerate Update Hashes</a><br /><br />
<a href="{{ path('moderation.system.migration.difficultyRating') }}" class="button">Regenerate Difficulty Ratings</a>
</div>
</section>
{% endblock %}
......
......@@ -4,12 +4,57 @@
{% block content %}
<section class="section-search">
<header>
<div class="title">Search</div>
<div class="actions">
<a href="{{ path('search.index', {showAll: true}) }}" class="button">Show all</a>
</div>
</header>
<div class="search-filters">
<form action="" method="get">
<input type="hidden" name="q" value="{{ searchQuery }}" />
<header>Difficulties Included</header>
<div class="filter-input">
<label class="filter-difficulty">
<input type="checkbox" name="diffEasy" {{ filterEasy ? 'checked' : '' }} />
<span></span>
<div>Easy</div>
</label>
<label class="filter-difficulty">
<input type="checkbox" name="diffNormal" {{ filterNormal ? 'checked' : '' }} />
<span></span>
<div>Normal</div>
</label>
<label class="filter-difficulty">
<input type="checkbox" name="diffHard" {{ filterHard ? 'checked' : '' }} />
<span></span>
<div>Hard</div>
</label>
<label class="filter-difficulty">
<input type="checkbox" name="diffExpert" {{ filterExpert ? 'checked' : '' }} />
<span></span>
<div>Expert</div>
</label>
<label class="filter-difficulty">
<input type="checkbox" name="diffXD" {{ filterXD ? 'checked' : '' }} />
<span></span>
<div>XD</div>
</label>
</div>
<header>Difficulty Rating</header>
<div class="filter-input">
<label class="filter-rating">
<input type="number" name="diffRatingFrom" value="{{ diffRatingFrom }}" />
<div>Minimal Rating</div>
</label>
<label class="filter-rating">
<input type="number" name="diffRatingTo" value="{{ diffRatingTo }}" />
<div>Maximum Rating</div>
</label>
</div>
<input type="submit" value="Filter" />
</form>
<!-- <a href="{{ path('search.index', {showAll: true}) }}" class="button">Show all</a> -->
</div>
{% if results is defined %}
<div class="search-results">
{% if results.users|length == 0 and results.songs|length == 0 %}
......@@ -40,7 +85,7 @@
{% endif %}
{% if results.songs|length > 0 %}
<div class="song-row search-results-songs">
<div class="song-list">
<div class="song-list-5">
{% for song in results.songs %}
{{ include('components/song-item.html.twig', {song: song}) }}
{% endfor %}
......
......@@ -84,11 +84,11 @@
<i class="mdi mdi-arm-flex"></i>
</div>
<div class="difficulties">
<img src="{{ asset('assets/img/difficultyEasy.svg') }}" class="{{ song.hasEasyDifficulty ? "active" : "" }}" alt="Easy Difficulty" />
<img src="{{ asset('assets/img/difficultyNormal.svg') }}" class="{{ song.hasNormalDifficulty ? "active" : "" }}" alt="Normal Difficulty" />
<img src="{{ asset('assets/img/difficultyHard.svg') }}" class="{{ song.hasHardDifficulty ? "active" : "" }}" alt="Hard Difficulty" />
<img src="{{ asset('assets/img/difficultyExtreme.svg') }}" class="{{ song.hasExtremeDifficulty ? "active" : "" }}" alt="Extreme Difficulty" />
<img src="{{ asset('assets/img/difficultyXD.svg') }}" class="{{ song.hasXDDifficulty ? "active" : "" }}" alt="xD Difficulty" />
{% if song.hasEasyDifficulty %}<div class="difficulty"><span>E</span> {{ song.easyDifficulty }}</div>{% endif %}
{% if song.hasNormalDifficulty %}<div class="difficulty"><span>N</span> {{ song.normalDifficulty }}</div>{% endif %}
{% if song.hasHardDifficulty %}<div class="difficulty"><span>H</span> {{ song.hardDifficulty }}</div>{% endif %}
{% if song.hasExtremeDifficulty %}<div class="difficulty"><span>EX</span> {{ song.expertDifficulty }}</div>{% endif %}
{% if song.hasXDDifficulty %}<div class="difficulty"><span>XD</span> {{ song.XDDifficulty }}</div>{% endif %}
</div>
</div>
{% if song.uploadDate|date("Y") > 2000 %}
......@@ -101,6 +101,16 @@
</div>
</div>
{% endif %}
{% if song.updateDate|date("Y") > 2000 %}
<div class="stat">
<div class="icon">
<i class="mdi mdi-pencil"></i>
</div>
<div class="content">
{{ song.updateDate|date("dS F Y") }}
</div>
</div>
{% endif %}
<div class="stat">
<div class="icon">
<i class="mdi mdi-eye"></i>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment