[IMP] php: cleaned up controller and added to GUI

refactor_total
Brett Spaulding 1 year ago
parent 0d3fd0fcd0
commit 6e72129ee7

@ -13,7 +13,10 @@ use Facebook\WebDriver\WebDriverBy;
class SearchController extends Controller
{
protected function getArtist($driver)
public $defaultArtistData = ['id', 'name', 'thumbnail', 'url_remote'];
protected function scrapeArtist($driver)
{
$response = [];
$artistContainer = $driver->findElement(WebDriverBy::cssSelector('.main-card-content-container'));
@ -22,24 +25,16 @@ class SearchController extends Controller
$artistHref = $artistLink[0]->getAttribute('href');
$artistName = $artistLink[0]->getAttribute('title');
if ($artistHref && $artistThumbnail && $artistName) {
$existingArtist = Artist::findByName($artistName)->first();
if (!$existingArtist) {
$artist_id = new Artist();
$artist_id->name = $artistName;
$artist_id->thumbnail = $artistThumbnail;
$artist_id->url_remote = $artistHref;
$artist_id->save();
$response[] = $this->buildResponse($artist_id);
} elseif (!$existingArtist->selected) {
$this->buildResponse($existingArtist);
}
}
return $response;
$data = [
'name' => $artistName,
'thumbnail' => $artistThumbnail,
'url_remote' => $artistHref,
];
$artist_id = Artist::findOrCreateByName($artistName, $data);
return $artist_id->read($this->defaultArtistData);
}
protected function getArtists($driver)
protected function scrapeArtists($driver)
{
$response = [];
// Click the artist button to force a "structure" of results
@ -47,7 +42,6 @@ class SearchController extends Controller
$driver->wait(10, 500)->until(
WebDriverExpectedCondition::visibilityOfElementLocated(WebDriverBy::xpath($artistBtnXpath))
);
$driver->findElement(WebDriverBy::xpath($artistBtnXpath))->click();
// Youtube has multiple elements with the same ID (Naughty!). We will give a reasonable analog time to render.
sleep(5);
@ -56,7 +50,6 @@ class SearchController extends Controller
$divCount = 0;
foreach ($contentDivs as $content) {
$divCount += 1;
$artists = $content->findElements(WebDriverBy::xpath('//ytmusic-responsive-list-item-renderer'));
if ($artists) {
$resultCap = 6;
@ -66,27 +59,19 @@ class SearchController extends Controller
$hasText = $artist->getText();
if ($hasText) {
$resultIndex += 1;
// Artist Details
$artistThumbnail = $artist->findElement(WebDriverBy::cssSelector('img'))->getAttribute('src');
$artistLink = $artist->findElements(WebDriverBy::cssSelector('a'));
$artistHref = $artistLink[0]->getAttribute('href');
$artistName = $artistLink[0]->getAttribute('aria-label');
$existingArtist = Artist::findByName($artistName)->first();
if (!$existingArtist) {
$artist_id = new Artist();
$artist_id->name = $artistName;
$artist_id->thumbnail = $artistThumbnail;
$artist_id->url_remote = $artistHref;
$artist_id->save();
\Log::info('New Artist added: ' . $artist_id->name);
$response[] = $this->buildResponse($artist_id);
} elseif ($existingArtist->exists() && !$existingArtist->selected) {
// Send the unselected artists back to client as suggestions
\Log::info('Artist already found' . $existingArtist->name);
$response[] = $this->buildResponse($existingArtist);
}
// Create if we don't have it yet
$data = [
'name' => $artistName,
'thumbnail' => $artistThumbnail,
'url_remote' => $artistHref,
];
$artist_id = Artist::findOrCreateByName($artistName, $data);
$response[] = $artist_id->read($this->defaultArtistData);
// Limit the results, there are alot of them
if ($resultCap <= $resultIndex) {
break;
@ -97,21 +82,11 @@ class SearchController extends Controller
if ($divCount === 1) {
break;
}
}
}
return $response;
}
protected static function buildResponse($artist_id)
{
return [
'name' => $artist_id->name,
'url_remote' => $artist_id->url_remote,
'thumbnail' => $artist_id->thumbnail,
];
}
protected function setUp()
{
$host = 'http://selenium-hub:4444';
@ -125,7 +100,7 @@ class SearchController extends Controller
return $driver;
}
public function search_artist(Request $request, string $artist)
public function search_artist(string $artist)
{
$response = [];
$url = 'https://music.youtube.com/search?q=' . str_replace(' ', '+', $artist);
@ -134,14 +109,13 @@ class SearchController extends Controller
// Add handling for no artist button; Some artists searches don't have this option (Ex The Black Dahlia Murder)
try {
$response = $this->getArtists($driver);
$response = $this->scrapeArtists($driver);
} catch (\Exception) {
\Log::warning('Could not get list of artists, attempting to get single artist card..');
$response = $this->getArtist($driver);
$response = $this->scrapeArtist($driver);
} finally {
$driver->quit();
}
return response()->json($response);
}
}

@ -14,4 +14,34 @@ class Artist extends Model
return self::where('name', '=', $name)->get();
}
public static function addArtist(string $name, string $thumbnail, string $url_remote)
{
$artist = new Artist();
$artist->name = $name;
$artist->url_remote = $url_remote;
$artist->thumbnail = $thumbnail;
$artist->save();
return $artist;
}
// TODO: discuss why I can't return Artist or Collection, because it failes either way but says its returning Artist
public static function findOrCreateByName(string $name, array $data = [])
{
$artist = self::findByName($name)->first();
if (!$artist && $data) {
$artist = self::addArtist($data['name'], $data['thumbnail'], $data['url_remote']);
}
return $artist;
}
public function read(array $fields = []): array
{
$data = $this->toArray();
// Filter
if ($fields) {
$data = array_intersect_key($data, array_flip(array_keys($fields)));
}
return $data;
}
}

@ -0,0 +1,781 @@
@charset "UTF-8";
:root {
--dt-row-selected: 13, 110, 253;
--dt-row-selected-text: 255, 255, 255;
--dt-row-selected-link: 9, 10, 11;
--dt-row-stripe: 0, 0, 0;
--dt-row-hover: 0, 0, 0;
--dt-column-ordering: 0, 0, 0;
--dt-html-background: white;
}
:root.dark {
--dt-html-background: rgb(33, 37, 41);
}
table.dataTable td.dt-control {
text-align: center;
cursor: pointer;
}
table.dataTable td.dt-control:before {
display: inline-block;
box-sizing: border-box;
content: "";
border-top: 5px solid transparent;
border-left: 10px solid rgba(0, 0, 0, 0.5);
border-bottom: 5px solid transparent;
border-right: 0px solid transparent;
}
table.dataTable tr.dt-hasChild td.dt-control:before {
border-top: 10px solid rgba(0, 0, 0, 0.5);
border-left: 5px solid transparent;
border-bottom: 0px solid transparent;
border-right: 5px solid transparent;
}
html.dark table.dataTable td.dt-control:before,
:root[data-bs-theme=dark] table.dataTable td.dt-control:before,
:root[data-theme=dark] table.dataTable td.dt-control:before {
border-left-color: rgba(255, 255, 255, 0.5);
}
html.dark table.dataTable tr.dt-hasChild td.dt-control:before,
:root[data-bs-theme=dark] table.dataTable tr.dt-hasChild td.dt-control:before,
:root[data-theme=dark] table.dataTable tr.dt-hasChild td.dt-control:before {
border-top-color: rgba(255, 255, 255, 0.5);
border-left-color: transparent;
}
div.dt-scroll {
width: 100%;
}
div.dt-scroll-body thead tr,
div.dt-scroll-body tfoot tr {
height: 0;
}
div.dt-scroll-body thead tr th, div.dt-scroll-body thead tr td,
div.dt-scroll-body tfoot tr th,
div.dt-scroll-body tfoot tr td {
height: 0 !important;
padding-top: 0px !important;
padding-bottom: 0px !important;
border-top-width: 0px !important;
border-bottom-width: 0px !important;
}
div.dt-scroll-body thead tr th div.dt-scroll-sizing, div.dt-scroll-body thead tr td div.dt-scroll-sizing,
div.dt-scroll-body tfoot tr th div.dt-scroll-sizing,
div.dt-scroll-body tfoot tr td div.dt-scroll-sizing {
height: 0 !important;
overflow: hidden !important;
}
table.dataTable thead > tr > th:active,
table.dataTable thead > tr > td:active {
outline: none;
}
table.dataTable thead > tr > th.dt-orderable-asc span.dt-column-order:before, table.dataTable thead > tr > th.dt-ordering-asc span.dt-column-order:before,
table.dataTable thead > tr > td.dt-orderable-asc span.dt-column-order:before,
table.dataTable thead > tr > td.dt-ordering-asc span.dt-column-order:before {
position: absolute;
display: block;
bottom: 50%;
content: "▲";
content: "▲"/"";
}
table.dataTable thead > tr > th.dt-orderable-desc span.dt-column-order:after, table.dataTable thead > tr > th.dt-ordering-desc span.dt-column-order:after,
table.dataTable thead > tr > td.dt-orderable-desc span.dt-column-order:after,
table.dataTable thead > tr > td.dt-ordering-desc span.dt-column-order:after {
position: absolute;
display: block;
top: 50%;
content: "▼";
content: "▼"/"";
}
table.dataTable thead > tr > th.dt-orderable-asc, table.dataTable thead > tr > th.dt-orderable-desc, table.dataTable thead > tr > th.dt-ordering-asc, table.dataTable thead > tr > th.dt-ordering-desc,
table.dataTable thead > tr > td.dt-orderable-asc,
table.dataTable thead > tr > td.dt-orderable-desc,
table.dataTable thead > tr > td.dt-ordering-asc,
table.dataTable thead > tr > td.dt-ordering-desc {
position: relative;
padding-right: 30px;
}
table.dataTable thead > tr > th.dt-orderable-asc span.dt-column-order, table.dataTable thead > tr > th.dt-orderable-desc span.dt-column-order, table.dataTable thead > tr > th.dt-ordering-asc span.dt-column-order, table.dataTable thead > tr > th.dt-ordering-desc span.dt-column-order,
table.dataTable thead > tr > td.dt-orderable-asc span.dt-column-order,
table.dataTable thead > tr > td.dt-orderable-desc span.dt-column-order,
table.dataTable thead > tr > td.dt-ordering-asc span.dt-column-order,
table.dataTable thead > tr > td.dt-ordering-desc span.dt-column-order {
position: absolute;
right: 12px;
top: 0;
bottom: 0;
width: 12px;
}
table.dataTable thead > tr > th.dt-orderable-asc span.dt-column-order:before, table.dataTable thead > tr > th.dt-orderable-asc span.dt-column-order:after, table.dataTable thead > tr > th.dt-orderable-desc span.dt-column-order:before, table.dataTable thead > tr > th.dt-orderable-desc span.dt-column-order:after, table.dataTable thead > tr > th.dt-ordering-asc span.dt-column-order:before, table.dataTable thead > tr > th.dt-ordering-asc span.dt-column-order:after, table.dataTable thead > tr > th.dt-ordering-desc span.dt-column-order:before, table.dataTable thead > tr > th.dt-ordering-desc span.dt-column-order:after,
table.dataTable thead > tr > td.dt-orderable-asc span.dt-column-order:before,
table.dataTable thead > tr > td.dt-orderable-asc span.dt-column-order:after,
table.dataTable thead > tr > td.dt-orderable-desc span.dt-column-order:before,
table.dataTable thead > tr > td.dt-orderable-desc span.dt-column-order:after,
table.dataTable thead > tr > td.dt-ordering-asc span.dt-column-order:before,
table.dataTable thead > tr > td.dt-ordering-asc span.dt-column-order:after,
table.dataTable thead > tr > td.dt-ordering-desc span.dt-column-order:before,
table.dataTable thead > tr > td.dt-ordering-desc span.dt-column-order:after {
left: 0;
opacity: 0.125;
line-height: 9px;
font-size: 0.8em;
}
table.dataTable thead > tr > th.dt-orderable-asc, table.dataTable thead > tr > th.dt-orderable-desc,
table.dataTable thead > tr > td.dt-orderable-asc,
table.dataTable thead > tr > td.dt-orderable-desc {
cursor: pointer;
}
table.dataTable thead > tr > th.dt-orderable-asc:hover, table.dataTable thead > tr > th.dt-orderable-desc:hover,
table.dataTable thead > tr > td.dt-orderable-asc:hover,
table.dataTable thead > tr > td.dt-orderable-desc:hover {
outline: 2px solid rgba(0, 0, 0, 0.05);
outline-offset: -2px;
}
table.dataTable thead > tr > th.dt-ordering-asc span.dt-column-order:before, table.dataTable thead > tr > th.dt-ordering-desc span.dt-column-order:after,
table.dataTable thead > tr > td.dt-ordering-asc span.dt-column-order:before,
table.dataTable thead > tr > td.dt-ordering-desc span.dt-column-order:after {
opacity: 0.6;
}
table.dataTable thead > tr > th.sorting_desc_disabled span.dt-column-order:after, table.dataTable thead > tr > th.sorting_asc_disabled span.dt-column-order:before,
table.dataTable thead > tr > td.sorting_desc_disabled span.dt-column-order:after,
table.dataTable thead > tr > td.sorting_asc_disabled span.dt-column-order:before {
display: none;
}
table.dataTable thead > tr > th:active,
table.dataTable thead > tr > td:active {
outline: none;
}
div.dt-scroll-body > table.dataTable > thead > tr > th,
div.dt-scroll-body > table.dataTable > thead > tr > td {
overflow: hidden;
}
:root.dark table.dataTable thead > tr > th.dt-orderable-asc:hover, :root.dark table.dataTable thead > tr > th.dt-orderable-desc:hover,
:root.dark table.dataTable thead > tr > td.dt-orderable-asc:hover,
:root.dark table.dataTable thead > tr > td.dt-orderable-desc:hover,
:root[data-bs-theme=dark] table.dataTable thead > tr > th.dt-orderable-asc:hover,
:root[data-bs-theme=dark] table.dataTable thead > tr > th.dt-orderable-desc:hover,
:root[data-bs-theme=dark] table.dataTable thead > tr > td.dt-orderable-asc:hover,
:root[data-bs-theme=dark] table.dataTable thead > tr > td.dt-orderable-desc:hover {
outline: 2px solid rgba(255, 255, 255, 0.05);
}
div.dt-processing {
position: absolute;
top: 50%;
left: 50%;
width: 200px;
margin-left: -100px;
margin-top: -22px;
text-align: center;
padding: 2px;
z-index: 10;
}
div.dt-processing > div:last-child {
position: relative;
width: 80px;
height: 15px;
margin: 1em auto;
}
div.dt-processing > div:last-child > div {
position: absolute;
top: 0;
width: 13px;
height: 13px;
border-radius: 50%;
background: rgb(13, 110, 253);
background: rgb(var(--dt-row-selected));
animation-timing-function: cubic-bezier(0, 1, 1, 0);
}
div.dt-processing > div:last-child > div:nth-child(1) {
left: 8px;
animation: datatables-loader-1 0.6s infinite;
}
div.dt-processing > div:last-child > div:nth-child(2) {
left: 8px;
animation: datatables-loader-2 0.6s infinite;
}
div.dt-processing > div:last-child > div:nth-child(3) {
left: 32px;
animation: datatables-loader-2 0.6s infinite;
}
div.dt-processing > div:last-child > div:nth-child(4) {
left: 56px;
animation: datatables-loader-3 0.6s infinite;
}
@keyframes datatables-loader-1 {
0% {
transform: scale(0);
}
100% {
transform: scale(1);
}
}
@keyframes datatables-loader-3 {
0% {
transform: scale(1);
}
100% {
transform: scale(0);
}
}
@keyframes datatables-loader-2 {
0% {
transform: translate(0, 0);
}
100% {
transform: translate(24px, 0);
}
}
table.dataTable.nowrap th, table.dataTable.nowrap td {
white-space: nowrap;
}
table.dataTable th,
table.dataTable td {
box-sizing: border-box;
}
table.dataTable th.dt-left,
table.dataTable td.dt-left {
text-align: left;
}
table.dataTable th.dt-center,
table.dataTable td.dt-center {
text-align: center;
}
table.dataTable th.dt-right,
table.dataTable td.dt-right {
text-align: right;
}
table.dataTable th.dt-justify,
table.dataTable td.dt-justify {
text-align: justify;
}
table.dataTable th.dt-nowrap,
table.dataTable td.dt-nowrap {
white-space: nowrap;
}
table.dataTable th.dt-empty,
table.dataTable td.dt-empty {
text-align: center;
vertical-align: top;
}
table.dataTable th.dt-type-numeric, table.dataTable th.dt-type-date,
table.dataTable td.dt-type-numeric,
table.dataTable td.dt-type-date {
text-align: right;
}
table.dataTable thead th,
table.dataTable thead td,
table.dataTable tfoot th,
table.dataTable tfoot td {
text-align: left;
}
table.dataTable thead th.dt-head-left,
table.dataTable thead td.dt-head-left,
table.dataTable tfoot th.dt-head-left,
table.dataTable tfoot td.dt-head-left {
text-align: left;
}
table.dataTable thead th.dt-head-center,
table.dataTable thead td.dt-head-center,
table.dataTable tfoot th.dt-head-center,
table.dataTable tfoot td.dt-head-center {
text-align: center;
}
table.dataTable thead th.dt-head-right,
table.dataTable thead td.dt-head-right,
table.dataTable tfoot th.dt-head-right,
table.dataTable tfoot td.dt-head-right {
text-align: right;
}
table.dataTable thead th.dt-head-justify,
table.dataTable thead td.dt-head-justify,
table.dataTable tfoot th.dt-head-justify,
table.dataTable tfoot td.dt-head-justify {
text-align: justify;
}
table.dataTable thead th.dt-head-nowrap,
table.dataTable thead td.dt-head-nowrap,
table.dataTable tfoot th.dt-head-nowrap,
table.dataTable tfoot td.dt-head-nowrap {
white-space: nowrap;
}
table.dataTable tbody th.dt-body-left,
table.dataTable tbody td.dt-body-left {
text-align: left;
}
table.dataTable tbody th.dt-body-center,
table.dataTable tbody td.dt-body-center {
text-align: center;
}
table.dataTable tbody th.dt-body-right,
table.dataTable tbody td.dt-body-right {
text-align: right;
}
table.dataTable tbody th.dt-body-justify,
table.dataTable tbody td.dt-body-justify {
text-align: justify;
}
table.dataTable tbody th.dt-body-nowrap,
table.dataTable tbody td.dt-body-nowrap {
white-space: nowrap;
}
/*
* Table styles
*/
table.dataTable {
width: 100%;
margin: 0 auto;
border-spacing: 0;
/*
* Header and footer styles
*/
/*
* Body styles
*/
}
table.dataTable thead th,
table.dataTable tfoot th {
font-weight: bold;
}
table.dataTable > thead > tr > th,
table.dataTable > thead > tr > td {
padding: 10px;
border-bottom: 1px solid rgba(0, 0, 0, 0.3);
}
table.dataTable > thead > tr > th:active,
table.dataTable > thead > tr > td:active {
outline: none;
}
table.dataTable > tfoot > tr > th,
table.dataTable > tfoot > tr > td {
border-top: 1px solid rgba(0, 0, 0, 0.3);
padding: 10px 10px 6px 10px;
}
table.dataTable > tbody > tr {
background-color: transparent;
}
table.dataTable > tbody > tr:first-child > * {
border-top: none;
}
table.dataTable > tbody > tr:last-child > * {
border-bottom: none;
}
table.dataTable > tbody > tr.selected > * {
box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.9);
box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.9);
color: rgb(255, 255, 255);
color: rgb(var(--dt-row-selected-text));
}
table.dataTable > tbody > tr.selected a {
color: rgb(9, 10, 11);
color: rgb(var(--dt-row-selected-link));
}
table.dataTable > tbody > tr > th,
table.dataTable > tbody > tr > td {
padding: 8px 10px;
}
table.dataTable.row-border > tbody > tr > *, table.dataTable.display > tbody > tr > * {
border-top: 1px solid rgba(0, 0, 0, 0.15);
}
table.dataTable.row-border > tbody > tr:first-child > *, table.dataTable.display > tbody > tr:first-child > * {
border-top: none;
}
table.dataTable.row-border > tbody > tr.selected + tr.selected > td, table.dataTable.display > tbody > tr.selected + tr.selected > td {
border-top-color: rgba(13, 110, 253, 0.65);
border-top-color: rgba(var(--dt-row-selected), 0.65);
}
table.dataTable.cell-border > tbody > tr > * {
border-top: 1px solid rgba(0, 0, 0, 0.15);
border-right: 1px solid rgba(0, 0, 0, 0.15);
}
table.dataTable.cell-border > tbody > tr > *:first-child {
border-left: 1px solid rgba(0, 0, 0, 0.15);
}
table.dataTable.cell-border > tbody > tr:first-child > * {
border-top: 1px solid rgba(0, 0, 0, 0.3);
}
table.dataTable.stripe > tbody > tr:nth-child(odd) > *, table.dataTable.display > tbody > tr:nth-child(odd) > * {
box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.023);
box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-stripe), 0.023);
}
table.dataTable.stripe > tbody > tr:nth-child(odd).selected > *, table.dataTable.display > tbody > tr:nth-child(odd).selected > * {
box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.923);
box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.923);
}
table.dataTable.hover > tbody > tr:hover > *, table.dataTable.display > tbody > tr:hover > * {
box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.035);
box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.035);
}
table.dataTable.hover > tbody > tr.selected:hover > *, table.dataTable.display > tbody > tr.selected:hover > * {
box-shadow: inset 0 0 0 9999px #0d6efd !important;
box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-selected), 1) !important;
}
table.dataTable.order-column > tbody tr > .sorting_1,
table.dataTable.order-column > tbody tr > .sorting_2,
table.dataTable.order-column > tbody tr > .sorting_3, table.dataTable.display > tbody tr > .sorting_1,
table.dataTable.display > tbody tr > .sorting_2,
table.dataTable.display > tbody tr > .sorting_3 {
box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.019);
box-shadow: inset 0 0 0 9999px rgba(var(--dt-column-ordering), 0.019);
}
table.dataTable.order-column > tbody tr.selected > .sorting_1,
table.dataTable.order-column > tbody tr.selected > .sorting_2,
table.dataTable.order-column > tbody tr.selected > .sorting_3, table.dataTable.display > tbody tr.selected > .sorting_1,
table.dataTable.display > tbody tr.selected > .sorting_2,
table.dataTable.display > tbody tr.selected > .sorting_3 {
box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.919);
box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.919);
}
table.dataTable.display > tbody > tr:nth-child(odd) > .sorting_1, table.dataTable.order-column.stripe > tbody > tr:nth-child(odd) > .sorting_1 {
box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.054);
box-shadow: inset 0 0 0 9999px rgba(var(--dt-column-ordering), 0.054);
}
table.dataTable.display > tbody > tr:nth-child(odd) > .sorting_2, table.dataTable.order-column.stripe > tbody > tr:nth-child(odd) > .sorting_2 {
box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.047);
box-shadow: inset 0 0 0 9999px rgba(var(--dt-column-ordering), 0.047);
}
table.dataTable.display > tbody > tr:nth-child(odd) > .sorting_3, table.dataTable.order-column.stripe > tbody > tr:nth-child(odd) > .sorting_3 {
box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.039);
box-shadow: inset 0 0 0 9999px rgba(var(--dt-column-ordering), 0.039);
}
table.dataTable.display > tbody > tr:nth-child(odd).selected > .sorting_1, table.dataTable.order-column.stripe > tbody > tr:nth-child(odd).selected > .sorting_1 {
box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.954);
box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.954);
}
table.dataTable.display > tbody > tr:nth-child(odd).selected > .sorting_2, table.dataTable.order-column.stripe > tbody > tr:nth-child(odd).selected > .sorting_2 {
box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.947);
box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.947);
}
table.dataTable.display > tbody > tr:nth-child(odd).selected > .sorting_3, table.dataTable.order-column.stripe > tbody > tr:nth-child(odd).selected > .sorting_3 {
box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.939);
box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.939);
}
table.dataTable.display > tbody > tr.even > .sorting_1, table.dataTable.order-column.stripe > tbody > tr.even > .sorting_1 {
box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.019);
box-shadow: inset 0 0 0 9999px rgba(var(--dt-column-ordering), 0.019);
}
table.dataTable.display > tbody > tr.even > .sorting_2, table.dataTable.order-column.stripe > tbody > tr.even > .sorting_2 {
box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.011);
box-shadow: inset 0 0 0 9999px rgba(var(--dt-column-ordering), 0.011);
}
table.dataTable.display > tbody > tr.even > .sorting_3, table.dataTable.order-column.stripe > tbody > tr.even > .sorting_3 {
box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.003);
box-shadow: inset 0 0 0 9999px rgba(var(--dt-column-ordering), 0.003);
}
table.dataTable.display > tbody > tr.even.selected > .sorting_1, table.dataTable.order-column.stripe > tbody > tr.even.selected > .sorting_1 {
box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.919);
box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.919);
}
table.dataTable.display > tbody > tr.even.selected > .sorting_2, table.dataTable.order-column.stripe > tbody > tr.even.selected > .sorting_2 {
box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.911);
box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.911);
}
table.dataTable.display > tbody > tr.even.selected > .sorting_3, table.dataTable.order-column.stripe > tbody > tr.even.selected > .sorting_3 {
box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.903);
box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.903);
}
table.dataTable.display tbody tr:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1 {
box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.082);
box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.082);
}
table.dataTable.display tbody tr:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2 {
box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.074);
box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.074);
}
table.dataTable.display tbody tr:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3 {
box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.062);
box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-hover), 0.062);
}
table.dataTable.display tbody tr:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1 {
box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.982);
box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.982);
}
table.dataTable.display tbody tr:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2 {
box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.974);
box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.974);
}
table.dataTable.display tbody tr:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3 {
box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.962);
box-shadow: inset 0 0 0 9999px rgba(var(--dt-row-selected), 0.962);
}
table.dataTable.compact thead th,
table.dataTable.compact thead td,
table.dataTable.compact tfoot th,
table.dataTable.compact tfoot td,
table.dataTable.compact tbody th,
table.dataTable.compact tbody td {
padding: 4px;
}
div.dt-container div.dt-layout-row {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
margin: 0.75em 0;
}
div.dt-container div.dt-layout-row div.dt-layout-cell {
display: flex;
justify-content: space-between;
align-items: center;
}
div.dt-container div.dt-layout-row div.dt-layout-cell.dt-layout-start {
justify-content: flex-start;
margin-right: auto;
}
div.dt-container div.dt-layout-row div.dt-layout-cell.dt-layout-end {
justify-content: flex-end;
margin-left: auto;
}
div.dt-container div.dt-layout-row div.dt-layout-cell:empty {
display: none;
}
@media screen and (max-width: 767px) {
div.dt-container div.dt-layout-row:not(.dt-layout-table) {
display: block;
}
div.dt-container div.dt-layout-row:not(.dt-layout-table) div.dt-layout-cell {
display: block;
text-align: center;
}
div.dt-container div.dt-layout-row:not(.dt-layout-table) div.dt-layout-cell > * {
margin: 0.5em 0;
}
div.dt-container div.dt-layout-row:not(.dt-layout-table) div.dt-layout-cell.dt-layout-start {
margin-right: 0;
}
div.dt-container div.dt-layout-row:not(.dt-layout-table) div.dt-layout-cell.dt-layout-end {
margin-left: 0;
}
}
div.dt-container div.dt-layout-start > *:not(:last-child) {
margin-right: 1em;
}
div.dt-container div.dt-layout-end > *:not(:first-child) {
margin-left: 1em;
}
div.dt-container div.dt-layout-full {
width: 100%;
}
div.dt-container div.dt-layout-full > *:only-child {
margin-left: auto;
margin-right: auto;
}
div.dt-container div.dt-layout-table > div {
display: block !important;
}
@media screen and (max-width: 767px) {
div.dt-container div.dt-layout-start > *:not(:last-child) {
margin-right: 0;
}
div.dt-container div.dt-layout-end > *:not(:first-child) {
margin-left: 0;
}
}
/*
* Control feature layout
*/
div.dt-container {
position: relative;
clear: both;
}
div.dt-container .dt-search input {
border: 1px solid #aaa;
border-radius: 3px;
padding: 5px;
background-color: transparent;
color: inherit;
margin-left: 3px;
}
div.dt-container .dt-input {
border: 1px solid #aaa;
border-radius: 3px;
padding: 5px;
background-color: transparent;
color: inherit;
}
div.dt-container select.dt-input {
padding: 4px;
}
div.dt-container .dt-paging .dt-paging-button {
box-sizing: border-box;
display: inline-block;
min-width: 1.5em;
padding: 0.5em 1em;
margin-left: 2px;
text-align: center;
text-decoration: none !important;
cursor: pointer;
color: inherit !important;
border: 1px solid transparent;
border-radius: 2px;
background: transparent;
}
div.dt-container .dt-paging .dt-paging-button.current, div.dt-container .dt-paging .dt-paging-button.current:hover {
color: inherit !important;
border: 1px solid rgba(0, 0, 0, 0.3);
background-color: rgba(0, 0, 0, 0.05);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(230, 230, 230, 0.05)), color-stop(100%, rgba(0, 0, 0, 0.05))); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%); /* Chrome10+,Safari5.1+ */
background: -moz-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%); /* FF3.6+ */
background: -ms-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%); /* IE10+ */
background: -o-linear-gradient(top, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%); /* Opera 11.10+ */
background: linear-gradient(to bottom, rgba(230, 230, 230, 0.05) 0%, rgba(0, 0, 0, 0.05) 100%); /* W3C */
}
div.dt-container .dt-paging .dt-paging-button.disabled, div.dt-container .dt-paging .dt-paging-button.disabled:hover, div.dt-container .dt-paging .dt-paging-button.disabled:active {
cursor: default;
color: rgba(0, 0, 0, 0.5) !important;
border: 1px solid transparent;
background: transparent;
box-shadow: none;
}
div.dt-container .dt-paging .dt-paging-button:hover {
color: white !important;
border: 1px solid #111;
background-color: #111;
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111)); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, #585858 0%, #111 100%); /* Chrome10+,Safari5.1+ */
background: -moz-linear-gradient(top, #585858 0%, #111 100%); /* FF3.6+ */
background: -ms-linear-gradient(top, #585858 0%, #111 100%); /* IE10+ */
background: -o-linear-gradient(top, #585858 0%, #111 100%); /* Opera 11.10+ */
background: linear-gradient(to bottom, #585858 0%, #111 100%); /* W3C */
}
div.dt-container .dt-paging .dt-paging-button:active {
outline: none;
background-color: #0c0c0c;
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c)); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%); /* Chrome10+,Safari5.1+ */
background: -moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%); /* FF3.6+ */
background: -ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%); /* IE10+ */
background: -o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%); /* Opera 11.10+ */
background: linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%); /* W3C */
box-shadow: inset 0 0 3px #111;
}
div.dt-container .dt-paging .ellipsis {
padding: 0 1em;
}
div.dt-container .dt-length,
div.dt-container .dt-search,
div.dt-container .dt-info,
div.dt-container .dt-processing,
div.dt-container .dt-paging {
color: inherit;
}
div.dt-container .dataTables_scroll {
clear: both;
}
div.dt-container .dataTables_scroll div.dt-scroll-body {
-webkit-overflow-scrolling: touch;
}
div.dt-container .dataTables_scroll div.dt-scroll-body > table > thead > tr > th, div.dt-container .dataTables_scroll div.dt-scroll-body > table > thead > tr > td, div.dt-container .dataTables_scroll div.dt-scroll-body > table > tbody > tr > th, div.dt-container .dataTables_scroll div.dt-scroll-body > table > tbody > tr > td {
vertical-align: middle;
}
div.dt-container .dataTables_scroll div.dt-scroll-body > table > thead > tr > th > div.dataTables_sizing,
div.dt-container .dataTables_scroll div.dt-scroll-body > table > thead > tr > td > div.dataTables_sizing, div.dt-container .dataTables_scroll div.dt-scroll-body > table > tbody > tr > th > div.dataTables_sizing,
div.dt-container .dataTables_scroll div.dt-scroll-body > table > tbody > tr > td > div.dataTables_sizing {
height: 0;
overflow: hidden;
margin: 0 !important;
padding: 0 !important;
}
div.dt-container.dt-empty-footer tbody > tr:last-child > * {
border-bottom: 1px solid rgba(0, 0, 0, 0.3);
}
div.dt-container.dt-empty-footer .dt-scroll-body {
border-bottom: 1px solid rgba(0, 0, 0, 0.3);
}
div.dt-container.dt-empty-footer .dt-scroll-body tbody > tr:last-child > * {
border-bottom: none;
}
html.dark {
--dt-row-hover: 255, 255, 255;
--dt-row-stripe: 255, 255, 255;
--dt-column-ordering: 255, 255, 255;
}
html.dark table.dataTable > thead > tr > th,
html.dark table.dataTable > thead > tr > td {
border-bottom: 1px solid rgb(89, 91, 94);
}
html.dark table.dataTable > thead > tr > th:active,
html.dark table.dataTable > thead > tr > td:active {
outline: none;
}
html.dark table.dataTable > tfoot > tr > th,
html.dark table.dataTable > tfoot > tr > td {
border-top: 1px solid rgb(89, 91, 94);
}
html.dark table.dataTable.row-border > tbody > tr > *, html.dark table.dataTable.display > tbody > tr > * {
border-top: 1px solid rgb(64, 67, 70);
}
html.dark table.dataTable.row-border > tbody > tr:first-child > *, html.dark table.dataTable.display > tbody > tr:first-child > * {
border-top: none;
}
html.dark table.dataTable.row-border > tbody > tr.selected + tr.selected > td, html.dark table.dataTable.display > tbody > tr.selected + tr.selected > td {
border-top-color: rgba(13, 110, 253, 0.65);
border-top-color: rgba(var(--dt-row-selected), 0.65);
}
html.dark table.dataTable.cell-border > tbody > tr > th,
html.dark table.dataTable.cell-border > tbody > tr > td {
border-top: 1px solid rgb(64, 67, 70);
border-right: 1px solid rgb(64, 67, 70);
}
html.dark table.dataTable.cell-border > tbody > tr > th:first-child,
html.dark table.dataTable.cell-border > tbody > tr > td:first-child {
border-left: 1px solid rgb(64, 67, 70);
}
html.dark .dt-container.dt-empty-footer table.dataTable {
border-bottom: 1px solid rgb(89, 91, 94);
}
html.dark .dt-container .dt-search input,
html.dark .dt-container .dt-length select {
border: 1px solid rgba(255, 255, 255, 0.2);
background-color: var(--dt-html-background);
}
html.dark .dt-container .dt-paging .dt-paging-button.current, html.dark .dt-container .dt-paging .dt-paging-button.current:hover {
border: 1px solid rgb(89, 91, 94);
background: rgba(255, 255, 255, 0.15);
}
html.dark .dt-container .dt-paging .dt-paging-button.disabled, html.dark .dt-container .dt-paging .dt-paging-button.disabled:hover, html.dark .dt-container .dt-paging .dt-paging-button.disabled:active {
color: #666 !important;
}
html.dark .dt-container .dt-paging .dt-paging-button:hover {
border: 1px solid rgb(53, 53, 53);
background: rgb(53, 53, 53);
}
html.dark .dt-container .dt-paging .dt-paging-button:active {
background: #3a3a3a;
}
/*
* Overrides for RTL support
*/
*[dir=rtl] table.dataTable thead th,
*[dir=rtl] table.dataTable thead td,
*[dir=rtl] table.dataTable tfoot th,
*[dir=rtl] table.dataTable tfoot td {
text-align: right;
}
*[dir=rtl] table.dataTable th.dt-type-numeric, *[dir=rtl] table.dataTable th.dt-type-date,
*[dir=rtl] table.dataTable td.dt-type-numeric,
*[dir=rtl] table.dataTable td.dt-type-date {
text-align: left;
}
*[dir=rtl] div.dt-container div.dt-layout-cell.dt-start {
text-align: right;
}
*[dir=rtl] div.dt-container div.dt-layout-cell.dt-end {
text-align: left;
}
*[dir=rtl] div.dt-container div.dt-search input {
margin: 0 3px 0 0;
}

@ -14,6 +14,10 @@ $('#settings_btn').on('click', () => {
$('#modalSettings').modal('toggle');
})
$('#catalog_btn').on('click', () => {
$('#modalCatalog').modal('toggle');
})
$('#queue_btn').on('click', () => {
appModal.modal('toggle');
})
@ -61,12 +65,15 @@ document.addEventListener('alpine:init', () => {
console.log('Alpine:init');
Alpine.store('app', {
init() {
// TODO: Poll for artists and queue
this.Artists = [];
this.Queue = [];
this.ArtistResults = []
},
Artists: [],
Queue: false,
Artists: [], // Rendered in the 'Artists' menu
ArtistResults: [], // Rendered in the
Queue: [], // Rendered in the 'Queue' menu
});

File diff suppressed because it is too large Load Diff

@ -1,4 +1,5 @@
<script src="https://code.jquery.com/jquery-3.7.0.min.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"
crossorigin="anonymous"></script>
<script src="{{ asset('js/datatables.js') }}"></script>
<script src="{{ asset('js/app.js') }}"></script>

@ -0,0 +1,6 @@
<link href="https://cdn.jsdelivr.net/npm/modern-normalize@v2.0.0/modern-normalize.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"
crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href=" {{ asset('/css/line-awesome.min.css') }}"/>
<link rel="stylesheet" type="text/css" href="{{ asset('/css/style.css') }}"/>
<link rel="stylesheet" href="{{ asset('css/datatables.css') }}"/>

@ -1,5 +1,9 @@
<div id="action_list">
<span>
<a id="catalog_btn" href="#catalog" class="p-2">
<i class="las la-address-book"></i>
Catalog
</a>
<a id="queue_btn" href="#download-queue" class="p-2">
<i class="las la-list queue_btn"></i>
Queue

@ -4,20 +4,15 @@
<meta charset="UTF-8"/>
<title>getDiscography</title>
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<meta name="description" content=""/>
<link href="https://cdn.jsdelivr.net/npm/modern-normalize@v2.0.0/modern-normalize.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"
crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href=" {{ asset('/css/line-awesome.min.css') }}"/>
<link rel="stylesheet" type="text/css" href="{{ asset('/css/style.css') }}"/>
<meta name="description" content="The #1 Solution for Archiving Albums!"/>
<link rel="icon" type="image/png" sizes="32x32" href="{{ asset('favicon.svg') }}">
<link rel="icon" type="image/png" sizes="16x16" href="{{ asset('favicon.svg') }}">
<link rel="apple-touch-icon" type="image/png" sizes="180x180" href="{{ asset('favicon.svg') }}">
<link rel="icon" type="image/svg+xml" href="{{ asset('favicon.svg') }}">
<meta name="theme-color" content="#1db8d7">
@include('assets.styles')
@include('assets.scripts-header')
</head>
<body x-data="{}">
@ -42,6 +37,7 @@
</main>
<!-- Modals -->
@include('modals.modal-catalog')
@include('modals.modal-download-queue')
@include('modals.modal-settings')

@ -0,0 +1,22 @@
<!-- Catalog Modal -->
<div class="modal fade"
id="modalCatalog" tabindex="-1" aria-labelledby="modalCatalog" aria-hidden="true">
<div
class="modal-dialog modal-dialog-centered modal-fullscreen modal-dialog-scrollable modal-fullscreen-md-down modal-fullscreen-sm-down">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Catalog</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"
aria-label="Close"></button>
</div>
<div class="modal-body">
<div id="modal_content">
<div id="catalogDatatable"></div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
Loading…
Cancel
Save