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 { ...@@ -364,6 +364,11 @@ input[type="range"]::-ms-fill-lower {
grid-template-columns: repeat(6, 1fr); grid-template-columns: repeat(6, 1fr);
grid-gap: 15px; grid-gap: 15px;
} }
.song-row .song-list-5 {
display: grid;
grid-template-columns: repeat(5, 1fr);
grid-gap: 15px;
}
.song-row .pagination { .song-row .pagination {
text-align: right; text-align: right;
margin-top: 25px; margin-top: 25px;
...@@ -470,14 +475,10 @@ input[type="range"]::-ms-fill-lower { ...@@ -470,14 +475,10 @@ input[type="range"]::-ms-fill-lower {
padding: 3px 8px; padding: 3px 8px;
margin-right: 4px; margin-right: 4px;
font-size: 10px; font-size: 10px;
opacity: 0.3;
} }
.song-item .song-metadata .song-difficulties .difficulty span { .song-item .song-metadata .song-difficulties .difficulty span {
font-weight: bold; font-weight: bold;
} }
.song-item .song-metadata .song-difficulties .difficulty.active {
opacity: 1;
}
.song-item:not(.inactive):hover { .song-item:not(.inactive):hover {
cursor: pointer; cursor: pointer;
background: rgba(255, 255, 255, 0.2); background: rgba(255, 255, 255, 0.2);
...@@ -630,4 +631,3 @@ input[type="range"]::-ms-fill-lower { ...@@ -630,4 +631,3 @@ input[type="range"]::-ms-fill-lower {
grid-template-columns: repeat(6, 1fr); 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 { ...@@ -379,6 +379,11 @@ input[type="range"]::-ms-fill-lower {
grid-template-columns: repeat(6, 1fr); grid-template-columns: repeat(6, 1fr);
grid-gap: 15px; grid-gap: 15px;
} }
& .song-list-5 {
display: grid;
grid-template-columns: repeat(5, 1fr);
grid-gap: 15px;
}
& .pagination { & .pagination {
text-align: right; text-align: right;
margin-top: 25px; margin-top: 25px;
...@@ -494,16 +499,11 @@ input[type="range"]::-ms-fill-lower { ...@@ -494,16 +499,11 @@ input[type="range"]::-ms-fill-lower {
padding: 3px 8px; padding: 3px 8px;
margin-right: 4px; margin-right: 4px;
font-size: 10px; font-size: 10px;
opacity: 0.3;
& span { & span {
// padding-right: 3px; // padding-right: 3px;
font-weight: bold; font-weight: bold;
} }
&.active {
opacity: 1;
}
} }
} }
} }
......
.section-search { .section-search {
display: grid; display: grid;
grid-template-rows: auto 1fr; min-height: 100vh;
grid-gap: 25px; grid-template-rows: 1fr;
grid-template-columns: 350px 1fr;
grid-template-areas: "filters results";
} }
.section-search header { .section-search .search-filters {
background: rgba(0, 0, 0, 0.5); grid-area: filters;
padding: 50px; background: #101314;
padding-bottom: 25px; padding: 30px;
} }
.section-search header .title { .section-search .search-filters header {
font-size: 32px; font-size: 14px;
letter-spacing: 0.05em; letter-spacing: 0.25em;
font-weight: bold;
text-transform: uppercase; 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; display: grid;
grid-template-columns: 1fr auto; grid-template-columns: auto 1fr;
grid-gap: 15px; grid-gap: 10px;
margin-top: 10px;
cursor: pointer;
align-items: center; 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 { .section-search .search-filters .filter-input .filter-difficulty span::before {
height: 100%; transition: 0.2s ease-in-out all;
display: flex; content: "";
justify-content: center; 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; align-items: center;
padding: 0px 10px;
} }
.section-search header .actions input { .section-search .search-filters .filter-input .filter-rating div {
width: 100%; display: block;
position: relative;
}
.section-search .search-filters .filter-input .filter-rating input[type="number"] {
width: 75px;
font-family: 'Open Sans', sans-serif; font-family: 'Open Sans', sans-serif;
font-size: 14px; font-size: 14px;
background: transparent;
color: #fff; color: #fff;
border-radius: 4px; border-radius: 4px;
padding: 9px 20px; padding: 9px 20px;
...@@ -40,22 +88,54 @@ ...@@ -40,22 +88,54 @@
border: 0px; border: 0px;
transition: 0.2s ease-in-out all; 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); background: rgba(255, 255, 255, 0.3);
color: #fff; color: #fff;
} }
.section-search header .actions input:focus { .section-search .search-filters .filter-input .filter-rating input[type="number"]:focus {
outline: 0; outline: 0;
background: rgba(255, 255, 255, 0.3); background: rgba(255, 255, 255, 0.3);
} }
.section-search header .actions input::placeholder { .section-search .search-filters .filter-input .filter-rating input[type="number"]::placeholder {
color: rgba(255, 255, 255, 0.6); 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 { .section-search .search-results {
display: grid; display: grid;
grid-area: results;
grid-template-rows: auto auto auto 1fr; grid-template-rows: auto auto auto 1fr;
grid-gap: 25px; grid-gap: 25px;
padding: 0px 50px; padding: 30px;
} }
.section-search .search-results .search-results-users { .section-search .search-results .search-results-users {
display: grid; display: grid;
......
.section-search { .section-search {
display: grid; display: grid;
grid-template-rows: auto 1fr; min-height: 100vh;
grid-gap: 25px; grid-template-rows: 1fr;
grid-template-columns: 350px 1fr;
grid-template-areas: "filters results";
& header { & .search-filters {
background: rgba(0,0,0,0.5); grid-area: filters;
padding: 50px; background: #101314;
padding-bottom: 25px; padding: 30px;
& .title { & header {
font-size: 32px; font-size: 14px;
letter-spacing: 0.05em; letter-spacing: 0.25em;
font-weight: bold;
text-transform: uppercase; text-transform: uppercase;
margin-bottom: 15px;
font-family: 'Oswald', sans-serif;
} }
& .actions { & .filter-input {
margin-bottom: 25px;
& .filter-difficulty {
position: relative;
display: grid; display: grid;
grid-template-columns: 1fr auto; grid-template-columns: auto 1fr;
grid-gap: 15px; grid-gap: 10px;
margin-top: 10px;
cursor: pointer;
align-items: center; align-items: center;
overflow: hidden;
& 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);
}
}
& span {
height: 20px;
width: 40px;
background: rgba(255,255,255,0.2);
border-radius: 100px;
transition: 0.2s ease-in-out all;
& .show-all { &::before {
height: 100%; transition: 0.2s ease-in-out all;
display: flex; content: "";
justify-content: center; 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; align-items: center;
padding: 0px 10px;
& div {
display: block;
position: relative;
} }
input { & input[type="number"] {
width: 100%; width: 75px;
font-family: 'Open Sans', sans-serif; font-family: 'Open Sans', sans-serif;
font-size: 14px; font-size: 14px;
background: transparent;
color: #fff; color: #fff;
border-radius: 4px; border-radius: 4px;
padding: 9px 20px; padding: 9px 20px;
...@@ -50,17 +105,53 @@ ...@@ -50,17 +105,53 @@
background: rgba(255,255,255,0.3); background: rgba(255,255,255,0.3);
} }
&::placeholder { &::placeholder {
color: rgba(255,255,255,0.6); 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 { & .search-results {
display: grid; display: grid;
grid-area: results;
grid-template-rows: auto auto auto 1fr; grid-template-rows: auto auto auto 1fr;
grid-gap: 25px; grid-gap: 25px;
padding: 0px 50px; padding: 30px;
& .search-results-users { & .search-results-users {
display: grid; display: grid;
......
...@@ -125,14 +125,19 @@ ...@@ -125,14 +125,19 @@
} }
.section-song-detail .song-detail .song-statistics .stat .difficulties { .section-song-detail .song-detail .song-statistics .stat .difficulties {
align-self: center; align-self: center;
height: 20px;
display: flex;
} }
.section-song-detail .song-detail .song-statistics .stat .difficulties img { .section-song-detail .song-detail .song-statistics .stat .difficulties .difficulty {
height: 25px; background: #fff;
margin-right: 5px; color: #000;
opacity: 0.4; border-radius: 4px;
padding: 3px 8px;
margin-right: 4px;
font-size: 10px;
} }
.section-song-detail .song-detail .song-statistics .stat .difficulties img.active { .section-song-detail .song-detail .song-statistics .stat .difficulties .difficulty span {
opacity: 1; font-weight: bold;
} }
.section-song-detail .song-detail .song-statistics .stat .content { .section-song-detail .song-detail .song-statistics .stat .content {
align-self: center; align-self: center;
...@@ -687,4 +692,3 @@ ...@@ -687,4 +692,3 @@
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
} }
/*# sourceMappingURL=songdetail.css.map */
\ No newline at end of file
...@@ -143,14 +143,20 @@ ...@@ -143,14 +143,20 @@
& .difficulties { & .difficulties {
align-self: center; align-self: center;
height: 20px;
display: flex;
& img { & .difficulty {
height: 25px; background: #fff;
margin-right: 5px; color: #000;
opacity: 0.4; border-radius: 4px;
padding: 3px 8px;
margin-right: 4px;
font-size: 10px;
&.active { & span {
opacity: 1; // padding-right: 3px;
font-weight: bold;
} }
} }
} }
......
...@@ -47,20 +47,54 @@ class IndexController extends AbstractController ...@@ -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(); $em = $this->getDoctrine()->getManager();
$data = []; $data = [];
$hotOffset = $request->query->get('hotOffset') ? $request->query->get('hotOffset') : 0; $updatedOffset = $request->query->get('updatedOffset') ? $request->query->get('updatedOffset') : 0;
$resultsHotSongs = $em->getRepository(Song::class)->getHot($hotOffset); $resultsUpdatedSongs = $em->getRepository(Song::class)->getUpdated($updatedOffset);
$data['hotSongs'] = $resultsHotSongs; $data['updatedSongs'] = $resultsUpdatedSongs;
$data['hotOffset'] = $hotOffset; $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 ...@@ -83,7 +83,7 @@ class ClientReleasesController extends AbstractController
$em->persist($newRelease); $em->persist($newRelease);
$em->flush(); $em->flush();
return $this->redirectToRoute('moderation.index'); return $this->redirectToRoute('moderation.clientreleases.index');
} catch(FileException $e) { } catch(FileException $e) {
} }
...@@ -118,6 +118,6 @@ class ClientReleasesController extends AbstractController ...@@ -118,6 +118,6 @@ class ClientReleasesController extends AbstractController
$em->remove($releaseToRemove); $em->remove($releaseToRemove);
$em->flush(); $em->flush();
return $this->redirectToRoute('moderation.index'); return $this->redirectToRoute('moderation.clientreleases.index');
} }
} }
...@@ -127,8 +127,163 @@ class SystemController extends AbstractController ...@@ -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; 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'); 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 ...@@ -30,6 +30,15 @@ class SearchController extends AbstractController
$data['results']['users'] = $resultsUsers; $data['results']['users'] = $resultsUsers;
$data['results']['songs'] = $resultsSongs; $data['results']['songs'] = $resultsSongs;
$filterEasy = true;
$filterNormal = true;
$filterHard = true;
$filterExpert = true;
$filterXD = true;
$filterMinDifficulty = 0;
$filterMaxDifficulty = 99;
} else { } else {
if($searchQuery != null) { if($searchQuery != null) {
$resultsUsers = $em->getRepository(User::class)->createQueryBuilder('o') $resultsUsers = $em->getRepository(User::class)->createQueryBuilder('o')
...@@ -39,24 +48,78 @@ class SearchController extends AbstractController ...@@ -39,24 +48,78 @@ class SearchController extends AbstractController
->getQuery() ->getQuery()
->getResult(); ->getResult();
$resultsSongs = $em->getRepository(Song::class)->createQueryBuilder('o');
$resultsSongs = $em->getRepository(Song::class)->createQueryBuilder('o') $resultsSongs->where('o.title LIKE :query');
->where('o.title LIKE :query') $resultsSongs->orWhere('o.subtitle LIKE :query');
->orWhere('o.subtitle LIKE :query') $resultsSongs->orWhere('o.tags LIKE :query');
->orWhere('o.tags LIKE :query') $resultsSongs->orWhere('o.artist LIKE :query');
->orWhere('o.artist LIKE :query') $resultsSongs->orWhere('o.charter LIKE :query');
->orWhere('o.charter LIKE :query')
->andWhere('o.publicationStatus IN (0, 1)') // Add Filters for difficulty
->orderBy('o.id', 'DESC') $filterEasy = $request->query->get('diffEasy') == 'on' ? true : false;
->setParameter('query', '%'.$searchQuery.'%') $filterNormal = $request->query->get('diffNormal') == 'on' ? true : false;
->getQuery() $filterHard = $request->query->get('diffHard') == 'on' ? true : false;
->getResult(); $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']['users'] = $resultsUsers;
$data['results']['songs'] = $resultsSongs; $data['results']['songs'] = $filteredResultsSongs;
} }
} }
$data['searchQuery'] = $searchQuery; $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); return $this->render('search/index.html.twig', $data);
} }
......
...@@ -231,6 +231,7 @@ class SongController extends AbstractController ...@@ -231,6 +231,7 @@ class SongController extends AbstractController
$song->setTags($data['tags']); $song->setTags($data['tags']);
$song->setDescription($data['description']); $song->setDescription($data['description']);
$song->setIsExplicit($data['isExplicit']); $song->setIsExplicit($data['isExplicit']);
$song->setUpdateDate(new \DateTime('NOW'));
$song->setPublicationStatus($data['publicationStatus']); $song->setPublicationStatus($data['publicationStatus']);
if($backupFile) { if($backupFile) {
...@@ -305,12 +306,23 @@ class SongController extends AbstractController ...@@ -305,12 +306,23 @@ class SongController extends AbstractController
$song->setArtist($trackInfo->artistName); $song->setArtist($trackInfo->artistName);
$song->setCharter($trackInfo->charter); $song->setCharter($trackInfo->charter);
// Generate new UpdateHash
$song->setUpdateHash(md5(json_encode($srtbContent)));
// Reset Difficulty Ratings
$song->setHasEasyDifficulty(false); $song->setHasEasyDifficulty(false);
$song->setHasNormalDifficulty(false); $song->setHasNormalDifficulty(false);
$song->setHasHardDifficulty(false); $song->setHasHardDifficulty(false);
$song->setHasExtremeDifficulty(false); $song->setHasExtremeDifficulty(false);
$song->setHasXDDifficulty(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) { foreach($trackInfo->difficulties as $oneData) {
if(isset($oneData->_active) && $oneData->_active || !isset($oneData->_active)) { if(isset($oneData->_active) && $oneData->_active || !isset($oneData->_active)) {
switch($oneData->_difficulty) { switch($oneData->_difficulty) {
...@@ -332,6 +344,27 @@ class SongController extends AbstractController ...@@ -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) { } catch(Exception $e) {
var_dump($e); var_dump($e);
......
...@@ -101,6 +101,9 @@ class UploadController extends AbstractController ...@@ -101,6 +101,9 @@ class UploadController extends AbstractController
$song->setHasExtremeDifficulty(false); $song->setHasExtremeDifficulty(false);
$song->setHasXDDifficulty(false); $song->setHasXDDifficulty(false);
$song->setUpdateHash(md5(json_encode($srtbContent)));
// Detect used difficulties
foreach($trackInfo->difficulties as $oneData) { foreach($trackInfo->difficulties as $oneData) {
if(isset($oneData->_active) && $oneData->_active || !isset($oneData->_active)) { if(isset($oneData->_active) && $oneData->_active || !isset($oneData->_active)) {
switch($oneData->_difficulty) { switch($oneData->_difficulty) {
...@@ -122,7 +125,31 @@ class UploadController extends AbstractController ...@@ -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) { } catch(Exception $e) {
var_dump($e);
exit;
$this->addFlash('error', 'Uploading failed. Please report back to our development team!'); $this->addFlash('error', 'Uploading failed. Please report back to our development team!');
// clean up temp files // clean up temp files
......
...@@ -99,11 +99,41 @@ class Song ...@@ -99,11 +99,41 @@ class Song
*/ */
private $hasXDDifficulty; 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") * @ORM\Column(type="datetime")
*/ */
private $uploadDate; private $uploadDate;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $updateHash;
/** /**
* @ORM\Column(type="text", nullable=true) * @ORM\Column(type="text", nullable=true)
*/ */
...@@ -124,6 +154,11 @@ class Song ...@@ -124,6 +154,11 @@ class Song
*/ */
private $songPlaylists; private $songPlaylists;
/**
* @ORM\Column(type="datetime", nullable=true)
*/
private $updateDate;
public function __construct() public function __construct()
{ {
$this->reviews = new ArrayCollection(); $this->reviews = new ArrayCollection();
...@@ -333,6 +368,86 @@ class Song ...@@ -333,6 +368,86 @@ class Song
return $this; 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 public function getUploadDate(): ?DateTimeInterface
{ {
return $this->uploadDate; return $this->uploadDate;
...@@ -345,6 +460,18 @@ class Song ...@@ -345,6 +460,18 @@ class Song
return $this; return $this;
} }
public function getUpdateHash(): ?string
{
return $this->updateHash;
}
public function setUpdateHash(?string $updateHash): self
{
$this->updateHash = $updateHash;
return $this;
}
public function getDescription(): ?string public function getDescription(): ?string
{ {
return $this->description; return $this->description;
...@@ -438,7 +565,14 @@ class Song ...@@ -438,7 +565,14 @@ class Song
'hasHardDifficulty' => $this->hasHardDifficulty, 'hasHardDifficulty' => $this->hasHardDifficulty,
'hasExtremeDifficulty' => $this->hasExtremeDifficulty, 'hasExtremeDifficulty' => $this->hasExtremeDifficulty,
'hasXDDifficulty' => $this->hasXDDifficulty, 'hasXDDifficulty' => $this->hasXDDifficulty,
'easyDifficulty' => $this->easyDifficulty,
'normalDifficulty' => $this->normalDifficulty,
'hardDifficulty' => $this->hardDifficulty,
'expertDifficulty' => $this->expertDifficulty,
'XDDifficulty' => $this->XDDifficulty,
'uploadDate' => $this->uploadDate, 'uploadDate' => $this->uploadDate,
'updateDate' => $this->updateDate,
'updateHash' => $this->updateHash,
'description' => $this->description 'description' => $this->description
); );
} }
...@@ -470,4 +604,16 @@ class Song ...@@ -470,4 +604,16 @@ class Song
return $this; return $this;
} }
public function getUpdateDate(): ?\DateTimeInterface
{
return $this->updateDate;
}
public function setUpdateDate(?\DateTimeInterface $updateDate): self
{
$this->updateDate = $updateDate;
return $this;
}
} }
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
private $reviews; private $reviews;
/** /**
* @ORM\ManyToMany(targetEntity="App\Entity\SongSpinPlay", mappedBy="user") * @ORM\OneToMany(targetEntity="App\Entity\SongSpinPlay", mappedBy="user")
*/ */
private $spinPlays; private $spinPlays;
......
...@@ -24,12 +24,23 @@ class SongRepository extends ServiceEntityRepository ...@@ -24,12 +24,23 @@ class SongRepository extends ServiceEntityRepository
$qb $qb
->where('e.publicationStatus = 0') ->where('e.publicationStatus = 0')
->orderBy('e.uploadDate', 'DESC') ->orderBy('e.uploadDate', 'DESC')
->setFirstResult(12 * $page) ->setFirstResult(10 * $page)
->setMaxResults(12); ->setMaxResults(10);
return $qb->getQuery()->getResult(); 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 = $this->createQueryBuilder("e");
$qb $qb
->where('e.publicationStatus = 0') ->where('e.publicationStatus = 0')
...@@ -37,13 +48,28 @@ class SongRepository extends ServiceEntityRepository ...@@ -37,13 +48,28 @@ class SongRepository extends ServiceEntityRepository
->andWhere('e.uploadDate >= :end') ->andWhere('e.uploadDate >= :end')
->orderBy('e.downloads', 'DESC') ->orderBy('e.downloads', 'DESC')
->addOrderBy('e.views', 'DESC') ->addOrderBy('e.views', 'DESC')
->setFirstResult(12 * $page) ->setFirstResult(10 * $page)
->setMaxResults(12) ->setMaxResults(10)
->setParameter('begin', new \DateTime('NOW')) ->setParameter('begin', new \DateTime('NOW'))
->setParameter('end', new \DateTime('-7 days')); ->setParameter('end', new \DateTime('-7 days'));
return $qb->getQuery()->getResult(); 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) { public function getPopular(int $page) {
return []; return [];
} }
......
...@@ -26,29 +26,34 @@ ...@@ -26,29 +26,34 @@
<div class="alert alert-primary" role="alert"> <div class="alert alert-primary" role="alert">
<h4 class="alert-heading">Last Update</h4> <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>
<div class="card"> <div class="card">
<h2 class="card-title">11/28/2020</h2> <h2 class="card-title">01/22/2021</h2>
<ul> <ul>
<li>Deprecated the Open Discovery->Popular endpoint</li> <li>Removed the Open Discovery->Popular endpoint</li>
<li>Added a link to the main website</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> </ul>
</div> </div>
<div class="card"> <div class="card">
<h2 class="card-title">11/02/2020</h2> <h2 class="card-title">11/28/2020</h2>
<ul> <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> </ul>
</div> </div>
<div class="card"> <div class="card">
<h2 class="card-title">10/14/2020</h2> <h2 class="card-title">11/02/2020</h2>
<ul> <ul>
<li>Updated Tournament output</li> <li>Added preferred pronouns for user profiles</li>
<lI>Added Playlists</lI>
</ul> </ul>
</div> </div>
</div> </div>
......
...@@ -25,7 +25,14 @@ ...@@ -25,7 +25,14 @@
</tr> </tr>
<tr> <tr>
<th>JSON Body</th> <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> </tr>
</table> </table>
...@@ -60,6 +67,12 @@ ...@@ -60,6 +67,12 @@
"hasHardDifficulty":false, "hasHardDifficulty":false,
"hasExtremeDifficulty":false, "hasExtremeDifficulty":false,
"hasXDDifficulty":true, "hasXDDifficulty":true,
"easyDifficulty": 5,
"normalDifficulty": 10,
"hardDifficulty": 15,
"expertDifficulty": 23,
"XDDifficulty": 26,
"updateHash": "d837d2adcdc19d215130cd92f27ae927",
"cover":"https:\/\/spinsha.re\/uploads\/thumbnail\/spinshare_5f2d157f6e44a.jpg", "cover":"https:\/\/spinsha.re\/uploads\/thumbnail\/spinshare_5f2d157f6e44a.jpg",
"zip":"https:\/\/spinsha.re\/api\/song\/1024\/download" "zip":"https:\/\/spinsha.re\/api\/song\/1024\/download"
}, },
...@@ -128,7 +141,7 @@ ...@@ -128,7 +141,7 @@
<div class="card" id="new"> <div class="card" id="new">
<h2 class="card-title">New Songs</h2> <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"> <table class="table table-bordered">
<tr> <tr>
...@@ -160,6 +173,12 @@ ...@@ -160,6 +173,12 @@
"hasHardDifficulty": true, "hasHardDifficulty": true,
"hasExtremeDifficulty": false, "hasExtremeDifficulty": false,
"hasXDDifficulty": false, "hasXDDifficulty": false,
"easyDifficulty": 5,
"normalDifficulty": 10,
"hardDifficulty": 15,
"expertDifficulty": 23,
"XDDifficulty": 26,
"updateHash": "d837d2adcdc19d215130cd92f27ae927",
"cover":"https:\/\/spinsha.re\/uploads\/thumbnail\/spinshare_5e8df6fb90bd7.jpg", "cover":"https:\/\/spinsha.re\/uploads\/thumbnail\/spinshare_5e8df6fb90bd7.jpg",
"zip":"https:\/\/spinsha.re\/api\/song\/3\/download" "zip":"https:\/\/spinsha.re\/api\/song\/3\/download"
}, },
...@@ -180,9 +199,9 @@ ...@@ -180,9 +199,9 @@
</pre> </pre>
</div> </div>
<div class="card" id="hot"> <div class="card" id="updated">
<h2 class="card-title">Hot Songs</h2> <h2 class="card-title">Updated Songs</h2>
<p>Returns the 12 most popular songs from the last 7 days. Use <code class="code">offset</code> for pagination.</p> <p>Returns 10 songs that were last updated. Use <code class="code">offset</code> for pagination.</p>
<table class="table table-bordered"> <table class="table table-bordered">
<tr> <tr>
...@@ -191,7 +210,7 @@ ...@@ -191,7 +210,7 @@
</tr> </tr>
<tr> <tr>
<th>Endpoint</th> <th>Endpoint</th>
<td>/songs/hot/<code class="code">offset</code></td> <td>/songs/updated/<code class="code">offset</code></td>
</tr> </tr>
</table> </table>
...@@ -214,6 +233,12 @@ ...@@ -214,6 +233,12 @@
"hasHardDifficulty": true, "hasHardDifficulty": true,
"hasExtremeDifficulty": false, "hasExtremeDifficulty": false,
"hasXDDifficulty": false, "hasXDDifficulty": false,
"easyDifficulty": 5,
"normalDifficulty": 10,
"hardDifficulty": 15,
"expertDifficulty": 23,
"XDDifficulty": 26,
"updateHash": "d837d2adcdc19d215130cd92f27ae927",
"cover":"https:\/\/spinsha.re\/uploads\/thumbnail\/spinshare_5e8df6fb90bd7.jpg", "cover":"https:\/\/spinsha.re\/uploads\/thumbnail\/spinshare_5e8df6fb90bd7.jpg",
"zip":"https:\/\/spinsha.re\/api\/song\/3\/download" "zip":"https:\/\/spinsha.re\/api\/song\/3\/download"
}, },
...@@ -234,9 +259,9 @@ ...@@ -234,9 +259,9 @@
</pre> </pre>
</div> </div>
<div class="card" id="popular"> <div class="card" id="hotThisWeek">
<h2 class="card-title">Popular Songs <span class="badge badge-secondary">deprecated</span></h2> <h2 class="card-title">Hot This Week Songs</h2>
<p>Returns the 12 most popular songs of all time. Use <code class="code">offset</code> for pagination.</p> <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"> <table class="table table-bordered">
<tr> <tr>
...@@ -245,16 +270,115 @@ ...@@ -245,16 +270,115 @@
</tr> </tr>
<tr> <tr>
<th>Endpoint</th> <th>Endpoint</th>
<td>/songs/popular/<code class="code">offset</code></td> <td>/songs/hot/<code class="code">offset</code></td>
</tr> </tr>
</table> </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 /> <br />
<div class="alert alert-secondary" role="alert">
<h4 class="alert-heading">Deprecated</h4> <strong>Output Body (Not Found)</strong>
This API-Endpoint was deprecated and should not be used anymore. <pre class="code">
{
"version":1,
"status":404,
"data":[]
}
</pre>
</div> </div>
<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>
<th>Method</th>
<td>GET</td>
</tr>
<tr>
<th>Endpoint</th>
<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 />
<strong>Output Body (Not Found)</strong>
<pre class="code">
{
"version":1,
"status":404,
"data":[]
}
</pre>
</div> </div>
</div> </div>
</div> </div>
<div class="col-lg-3"> <div class="col-lg-3">
...@@ -264,8 +388,9 @@ ...@@ -264,8 +388,9 @@
<a href="#search">Search</a> <a href="#search">Search</a>
<a href="#searchAll">Search All</a> <a href="#searchAll">Search All</a>
<a href="#new">New Songs</a> <a href="#new">New Songs</a>
<a href="#hot">Hot Songs</a> <a href="#updated">Updated Songs</a>
<a href="#popular">Popular Songs <span class="badge badge-secondary">Deprecated</span></a> <a href="#hotThisWeek">Hot This Week Songs</a>
<a href="#hotThisMonth">Hot This Month Songs</a>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -72,11 +72,24 @@ ...@@ -72,11 +72,24 @@
"hasHardDifficulty": false, "hasHardDifficulty": false,
"hasExtremeDifficulty": false, "hasExtremeDifficulty": false,
"hasXDDifficulty": true, "hasXDDifficulty": true,
"uploadDate": { "easyDifficulty": 5,
"date": "2020-10-14 12:50:25.000000", "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_type": 3,
"timezone": "Europe\/Berlin" "timezone": "Europe/Berlin"
}, },
"updateHash": "d837d2adcdc19d215130cd92f27ae927",
"description": null "description": null
} }
], ],
......
...@@ -37,46 +37,54 @@ ...@@ -37,46 +37,54 @@
<strong>Output Body</strong> <strong>Output Body</strong>
<pre class="code"> <pre class="code">
{ {
"version":1, "version": 1,
"status":200, "status": 200,
"data":{ "data":
"id":3, {
"title":"Isabelle Singing", "id": 10,
"subtitle":"K.K. Bubblegum", "title": "Shiny Days",
"artist":"K.K. Slider", "subtitle": "From \"Yuru Camp\"",
"charter":"Ellite", "artist": "Asaka",
"uploader":3, "charter": "imfallin",
"fileReference":"spinshare_5e8df6fb90bd7", "uploader": 1,
"tags":[ "fileReference": "spinshare_60018a36ec5e9",
"isabelle", "tags":
"singing", [
"easy", ""
"cute",
"animal",
"crossing",
"acnh",
"new",
"horizons"
], ],
"views":774, "views": 9,
"downloads":98, "downloads": null,
"isExplicit":false, "isExplicit": false,
"isTournament":false, "publicationStatus": 0,
"hasEasyDifficulty":false, "hasEasyDifficulty": true,
"hasNormalDifficulty":false, "hasNormalDifficulty": true,
"hasHardDifficulty":true, "hasHardDifficulty": true,
"hasExtremeDifficulty":false, "hasExtremeDifficulty": true,
"hasXDDifficulty":false, "hasXDDifficulty": true,
"uploadDate":{ "easyDifficulty": 5,
"date":"2020-05-01 00:00:00.000000", "normalDifficulty": 10,
"timezone_type":3, "hardDifficulty": 15,
"timezone":"Europe\/Berlin" "expertDifficulty": 23,
"XDDifficulty": 26,
"uploadDate":
{
"date": "2021-01-15 13:27:34.000000",
"timezone_type": 3,
"timezone": "Europe/Berlin"
}, },
"description":null, "updateDate":
"paths":{ {
"ogg":"https:\/\/spinsha.re\/uploads\/audio\/spinshare_5e8df6fb90bd7_0.ogg", "date": "2021-01-15 13:27:34.000000",
"cover":"https:\/\/spinsha.re\/uploads\/thumbnail\/spinshare_5e8df6fb90bd7.jpg", "timezone_type": 3,
"zip":"https:\/\/spinsha.re\/api\/song\/3\/download" "timezone": "Europe/Berlin"
},
"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 @@ ...@@ -48,6 +48,13 @@
<form action="{{ path('search.index') }}" method="GET" class="search"> <form action="{{ path('search.index') }}" method="GET" class="search">
<input name="q" type="search" placeholder="Search for songs, tags & profiles..." value="{{ searchQuery|default('') }}" /> <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> </form>
<nav class="items-right"> <nav class="items-right">
......
...@@ -8,16 +8,11 @@ ...@@ -8,16 +8,11 @@
<div class="song-title">{{ song.title|default('Untitled') }}</div> <div class="song-title">{{ song.title|default('Untitled') }}</div>
<div class="song-artist">{{ song.artist|default('Unknown') }}</div> <div class="song-artist">{{ song.artist|default('Unknown') }}</div>
<div class="song-difficulties"> <div class="song-difficulties">
<div class="difficulty {{ song.hasEasyDifficulty ? "active" : "" }}"><span>E</span></div> {% if song.hasEasyDifficulty %}<div class="difficulty"><span>E</span> {{ song.easyDifficulty }}</div>{% endif %}
<div class="difficulty {{ song.hasNormalDifficulty ? "active" : "" }}"><span>N</span></div> {% if song.hasNormalDifficulty %}<div class="difficulty"><span>N</span> {{ song.normalDifficulty }}</div>{% endif %}
<div class="difficulty {{ song.hasHardDifficulty ? "active" : "" }}"><span>H</span></div> {% if song.hasHardDifficulty %}<div class="difficulty"><span>H</span> {{ song.hardDifficulty }}</div>{% endif %}
<div class="difficulty {{ song.hasExtremeDifficulty ? "active" : "" }}"><span>EX</span></div> {% if song.hasExtremeDifficulty %}<div class="difficulty"><span>EX</span> {{ song.expertDifficulty }}</div>{% endif %}
<div class="difficulty {{ song.hasXDDifficulty ? "active" : "" }}"><span>XD</span></div> {% if song.hasXDDifficulty %}<div class="difficulty"><span>XD</span> {{ song.XDDifficulty }}</div>{% endif %}
<!-- <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" /> -->
</div> </div>
</div> </div>
</a> </a>
\ No newline at end of file
...@@ -8,7 +8,9 @@ ...@@ -8,7 +8,9 @@
<div class="tabs"> <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.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.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> </div>
</header> </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 @@ ...@@ -3,20 +3,20 @@
{% block indexContent %} {% block indexContent %}
<div class="song-row song-row-hot"> <div class="song-row song-row-hot">
<div class="song-list"> <div class="song-list">
{% for song in hotSongs %} {% for song in hotWeekSongs %}
{{ include('components/song-item.html.twig', {song: song}) }} {{ include('components/song-item.html.twig', {song: song}) }}
{% endfor %} {% endfor %}
</div> </div>
<div class="pagination"> <div class="pagination">
{% if hotOffset > 0 %} {% if hotWeekOffset > 0 %}
<a href="{{ path('index.hot', {hotOffset: hotOffset - 1}) }}" class="button"><i class="mdi mdi-chevron-left"></i> PREVIOUS</a> <a href="{{ path('index.hot', {hotWeekOffset: hotWeekOffset - 1}) }}" class="button"><i class="mdi mdi-chevron-left"></i> PREVIOUS</a>
{% else %} {% else %}
<a class="button button-disabled"><i class="mdi mdi-chevron-left"></i> PREVIOUS</a> <a class="button button-disabled"><i class="mdi mdi-chevron-left"></i> PREVIOUS</a>
{% endif %} {% endif %}
{% if hotSongs|length < 12 %} {% if hotWeekSongs|length < 12 %}
<a class="button button-disabled">NEXT <i class="mdi mdi-chevron-right"></i></a> <a class="button button-disabled">NEXT <i class="mdi mdi-chevron-right"></i></a>
{% else %} {% 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 %} {% endif %}
</div> </div>
</div> </div>
......
...@@ -82,7 +82,7 @@ ...@@ -82,7 +82,7 @@
</div> </div>
<div class="support-subsection"> <div class="support-subsection">
<h1>Our Patreons</h1> <h1>Our Patrons</h1>
<div class="user-list"> <div class="user-list">
{% for user in patreons %} {% for user in patreons %}
<a href="{{ path('user.detail', {userId: user.id}) }}" class="user-item"> <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 @@ ...@@ -17,8 +17,11 @@
<div class="box"> <div class="box">
Generate On All Songs Actions<br /><strong>(ATTENTION: They can take a while!)</strong><br /><br /> 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.generate.thumbnails') }}" class="button">Generate Thumbnails</a><br /><br />
<a href="{{ path('moderation.system.cleanup.temp') }}" class="button">Cleanup Temp Folder</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><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> </div>
</section> </section>
{% endblock %} {% endblock %}
......
...@@ -4,12 +4,57 @@ ...@@ -4,12 +4,57 @@
{% block content %} {% block content %}
<section class="section-search"> <section class="section-search">
<header> <div class="search-filters">
<div class="title">Search</div> <form action="" method="get">
<div class="actions"> <input type="hidden" name="q" value="{{ searchQuery }}" />
<a href="{{ path('search.index', {showAll: true}) }}" class="button">Show all</a>
<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> </div>
</header>
<input type="submit" value="Filter" />
</form>
<!-- <a href="{{ path('search.index', {showAll: true}) }}" class="button">Show all</a> -->
</div>
{% if results is defined %} {% if results is defined %}
<div class="search-results"> <div class="search-results">
{% if results.users|length == 0 and results.songs|length == 0 %} {% if results.users|length == 0 and results.songs|length == 0 %}
...@@ -40,7 +85,7 @@ ...@@ -40,7 +85,7 @@
{% endif %} {% endif %}
{% if results.songs|length > 0 %} {% if results.songs|length > 0 %}
<div class="song-row search-results-songs"> <div class="song-row search-results-songs">
<div class="song-list"> <div class="song-list-5">
{% for song in results.songs %} {% for song in results.songs %}
{{ include('components/song-item.html.twig', {song: song}) }} {{ include('components/song-item.html.twig', {song: song}) }}
{% endfor %} {% endfor %}
......
...@@ -84,11 +84,11 @@ ...@@ -84,11 +84,11 @@
<i class="mdi mdi-arm-flex"></i> <i class="mdi mdi-arm-flex"></i>
</div> </div>
<div class="difficulties"> <div class="difficulties">
<img src="{{ asset('assets/img/difficultyEasy.svg') }}" class="{{ song.hasEasyDifficulty ? "active" : "" }}" alt="Easy Difficulty" /> {% if song.hasEasyDifficulty %}<div class="difficulty"><span>E</span> {{ song.easyDifficulty }}</div>{% endif %}
<img src="{{ asset('assets/img/difficultyNormal.svg') }}" class="{{ song.hasNormalDifficulty ? "active" : "" }}" alt="Normal Difficulty" /> {% if song.hasNormalDifficulty %}<div class="difficulty"><span>N</span> {{ song.normalDifficulty }}</div>{% endif %}
<img src="{{ asset('assets/img/difficultyHard.svg') }}" class="{{ song.hasHardDifficulty ? "active" : "" }}" alt="Hard Difficulty" /> {% if song.hasHardDifficulty %}<div class="difficulty"><span>H</span> {{ song.hardDifficulty }}</div>{% endif %}
<img src="{{ asset('assets/img/difficultyExtreme.svg') }}" class="{{ song.hasExtremeDifficulty ? "active" : "" }}" alt="Extreme Difficulty" /> {% if song.hasExtremeDifficulty %}<div class="difficulty"><span>EX</span> {{ song.expertDifficulty }}</div>{% endif %}
<img src="{{ asset('assets/img/difficultyXD.svg') }}" class="{{ song.hasXDDifficulty ? "active" : "" }}" alt="xD Difficulty" /> {% if song.hasXDDifficulty %}<div class="difficulty"><span>XD</span> {{ song.XDDifficulty }}</div>{% endif %}
</div> </div>
</div> </div>
{% if song.uploadDate|date("Y") > 2000 %} {% if song.uploadDate|date("Y") > 2000 %}
...@@ -101,6 +101,16 @@ ...@@ -101,6 +101,16 @@
</div> </div>
</div> </div>
{% endif %} {% 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="stat">
<div class="icon"> <div class="icon">
<i class="mdi mdi-eye"></i> <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