Intial Project Commit

first commit to get all the project files in there
This commit is contained in:
Ro 2025-03-05 16:14:37 -06:00
parent 2ef0a5c932
commit b72650ed2f
55 changed files with 2628 additions and 0 deletions

24
.gitignore vendored Normal file
View file

@ -0,0 +1,24 @@
/.phpunit.cache
/node_modules
/vendor
.env
.env.backup
.env.production
.phpunit.result.cache
npm-debug.log
yarn-error.log
/.fleet
/.idea
/.vscode
/.parcel-cache
.env.local
/.env.local.php
/.env.*.local
/.nova
/assets/audio/tapes
*.DS_Store
*.codekit3

182
assets/css/front/index.css Normal file
View file

@ -0,0 +1,182 @@
main {
display: flex;
justify-content: center;
align-items: center;
padding: 15px;
transform-origin: 0 0;
perspective: 500px;
top: 50px;
position: relative;
}
header {
padding-top: 5px;
background: rgba(6, 9, 41, 0.5);
position: fixed;
z-index: 1000;
}
div.audio-progress {
width: 0;
height: 1px;
background: var(--primary);
position: relative;
margin: 0 auto;
}
article.tape-select {
transition: all 1s cubic-bezier(0.83, 0.05, 0.28, 1);
max-width: 800px;
margin: 0 auto;
padding: 10px;
backface-visibility: hidden;
position: absolute;
top: 1px;
}
article.tape-tracklist {
transition: all 1s cubic-bezier(0.83, 0.05, 0.28, 1);
max-width: 800px;
width: 100%;
margin: 0 auto;
padding: 10px;
position: absolute;
backface-visibility: hidden;
top: 5px;
padding-bottom: 60px;
}
img.the-logo {
width: 50px;
margin: 0 auto;
display: block;
}
img.covers {
padding-bottom: 2px;
border-radius: 3px;
width: 92px;
cursor: pointer;
}
img#tape-cover {
width: 350px;
margin: 0 auto;
display: block;
border-radius: 3px;
}
h1#tape-title {
width: 300px;
margin: 15px auto;
}
section#playlist {
width: 300px;
margin: 0 auto;
}
section#playlist div {
width: 100%;
display: inline-block;
font-size: 1em;
position: relative;
margin-bottom: 10px;
transition: all 0.5s cubic-bezier(0.83, 0.05, 0.28, 1);
}
section#playlist div label:nth-child(2) {
font-weight: bold;
color: var(--highlight);
}
section#playlist div label {
width: 100%;
display: inline-block;
font-size: 0.9em;
}
button.selectBtn {
height: 100%;
position: absolute;
width: 100%;
opacity: 0;
}
div#tape-controls {
background: var(--white);
width: 300px;
position: fixed;
z-index: 500;
height: 35px;
left: 50%;
transform: translate(-50%, -50%);
transition: all 1s cubic-bezier(0.83, 0.05, 0.28, 1);
border-radius: 20px;
display: flex;
border: 3px solid var(--white);
}
img.tape-control-button {
width: 35px;
display: flex;
}
label.control-text {
width: 73.6%;
color: var(--secondary);
position: relative;
text-transform: uppercase;
font-size: 0.65em;
font-weight: bold;
height: 100%;
line-height: 100%;
align-items: center;
display: flex;
background: var(--highlight);
border-radius: 3px;
padding: 0 5px;
margin: 0 5px;
}
.front {
transform: rotateY(0deg);
}
.back-right {
transform: rotateY(-180deg);
}
.back-left {
transform: rotateY(180deg);
}
.playing {
background: var(--white);
padding: 5px;
border-radius: 3px;
}
.not-playing {
background: none;
padding: 0;
border-radius: 0;
}
.label-playing {
color: var(--secondary);
}
.label-notplaying {
color: var(--white);
}
.control-open {
bottom: -17.5px;
opacity: 1;
}
.control-closed {
bottom: -55px;
opacity: 0;
}

View file

@ -0,0 +1,5 @@
@import "../global/colors.css";
@import "../global/forms.css";
@import "../global/typography.css";
@import "../global/frame.css";
@import "index.css";

View file

@ -0,0 +1,13 @@
:root {
/* BASE COLORS */
--primary: #ff0505;
--secondary: #03061e;
--highlight: #7ac1df;
--white: #efebe3;
--grey: #abb7b7;
--black: #32302f;
--error: #b62520;
--silence: #ea6010;
--suspend: #fb263a;
--primary-rgb: 20 13 13;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,47 @@
input[type="email"],
input[type="password"],
input[type="text"] {
border: 0;
padding: 5px;
border-radius: 5px;
font: 18px var(--base-type);
display: inline-block;
background: var(--white);
color: var(--primary);
transition: all 0.2s linear;
}
input[type="text"]:focus,
input[type="password"]:focus {
outline: solid var(--highlight);
background-color: var(--highlight);
}
textarea {
border: 0;
border-radius: 3px;
color: var(--primary);
background: var(--white);
}
button,
input[type="submit"] {
color: var(--white);
font: 1em var(--base-type);
border-radius: 5px;
position: relative;
cursor: pointer;
border: 0;
transition: all 0.3s linear;
padding: 0 0 10px;
text-align: left;
}
select {
font: 20px var(--base-type);
border-radius: 5px;
border: 1px solid var(--primary);
appearance: none;
color: var(--primary);
background: var(--secondary);
}

226
assets/css/global/frame.css Normal file
View file

@ -0,0 +1,226 @@
html {
width: 100%;
height: 100%;
overflow: hidden;
font: 400 1em/1em var(--base-type);
}
html body {
background: var(--secondary);
color: var(--white);
margin: 0;
padding: 0;
height: 100%;
width: 100%;
overflow-y: scroll;
overflow-x: hidden;
}
a {
color: var(--highlight);
text-decoration: none;
transition: all 0.2s linear;
/*
border-bottom: 1px solid var(--white);
*/
}
strong {
color: var(--primary);
}
header {
width: 100%;
color: var(--primary);
}
header > div:nth-child(1) {
display: grid;
grid-template-columns: 200px 1fr 40px;
padding: 10px;
gap: 10px;
height: 200px;
width: 80%;
margin: 0 auto;
max-width: 1000px;
position: relative;
}
header > div span {
font-size: 3em;
font-weight: bold;
position: absolute;
bottom: 25px;
width: 50%;
line-height: 0.8em;
}
header > div img {
width: 100%;
}
header > div a {
color: var(--primary);
}
header > div i {
font-size: 1.3em;
}
header > div nav {
background: var(--black);
position: relative;
}
.header-right {
text-align: right;
}
div.system-notice-error {
background: var(--error);
color: var(--white);
padding: 10px;
}
div.system-notice-message {
background: var(--highlight);
color: var(--black);
padding: 10px;
}
main > section > article {
width: 80%;
max-width: 1000px;
margin: 0 auto;
min-height: 400px;
}
/* NAV */
#main-nav {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: var(--black);
z-index: 1;
display: flex;
align-items: center;
justify-content: center;
}
label[for="element-toggle"] {
cursor: pointer;
}
#element-toggle {
display: none;
}
#element-toggle:not(:checked) ~ #main-nav {
display: none;
}
a.nav-links {
border-bottom: none;
font-size: 40px;
color: var(--highlight);
text-decoration: none;
}
/* GLOBALS */
a:hover {
/*
border-bottom: 1px solid var(--secondary);
*/
color: var(--white);
}
pre {
white-space: pre;
background: var(--secondary);
}
code {
background: var(--secondary);
color: var(--primary);
padding: 3px;
}
sup {
background: var(--black);
color: var(--white);
padding: 2px;
border-radius: 3px;
vertical-align: baseline;
font-family: var(--mono-type);
}
.button-icon {
height: 90%;
padding-top: 3px;
}
.menu-icon {
width: 40px;
}
.location-title {
display: none;
}
.location-image {
height: 200px;
width: 200px;
display: inline-block;
border-radius: 3px;
}
footer {
width: 100%;
color: var(--primary);
background: var(--secondary);
height: 200px;
}
footer > div:nth-child(1) {
display: grid;
grid-template-columns: 50% 50%;
padding: 10px;
gap: 10px;
height: 200px;
width: 80%;
margin: 0 auto;
max-width: 1000px;
position: relative;
}
/*
responsive
*/
@media only screen and (max-width: 960px) {
header > div:nth-child(1) {
}
header > div nav {
bottom: 17px;
}
}
@media only screen and (max-width: 960px) {
header > div:nth-child(1) {
grid-template-columns: 150px 65% 1fr;
height: 150px;
}
header > div nav {
bottom: 17px;
}
}
@media only screen and (max-width: 800px) {
}

View file

@ -0,0 +1,54 @@
/* RUBIK */
@font-face {
font-family: AlteHaasGrotesk;
src: url("fonts/ahg/AlteHaasGroteskRegular.ttf") format("truetype"),
url("fonts/ahg/AlteHaasGroteskRegular.woff") format("woff"),
url("fonts/ahg/AlteHaasGroteskRegular.woff2") format("woff2");
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: AlteHaasGrotesk;
src: url("fonts/ahg/AlteHaasGroteskBold.ttf") format("truetype"),
url("fonts/ahg/AlteHaasGroteskBold.woff") format("woff"),
url("fonts/ahg/AlteHaasGroteskBold.woff2") format("woff2");
font-weight: 700;
font-style: normal;
}
:root {
--base-type: AlteHaasGrotesk, helvetica, arial, sans-serif;
--mono-type: "Lucida Console", monaco, monospace;
}
p {
font: 400 1.2em/1.1em var(--base-type);
color: var(--white);
}
h1 {
font-size: 2em;
font-weight: 600;
font-kerning: normal;
letter-spacing: -3px;
text-transform: uppercase;
line-height: 0.75em;
margin: 0;
overflow-wrap: break-word;
color: var(--highlight);
}
h2 {
text-transform: lowercase;
font-size: 1.5em;
font-weight: 500;
line-height: 0.8em;
color: var(--primary);
margin: 15px 0;
}
h3 {
font-size: 1.5em;
font-weight: 300;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1,022 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated by Pixelmator Pro 3.3.8 -->
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path id="Path" fill="none" stroke="none" d="M 0 0 L 24 0 L 24 24 L 0 24 Z"/>
<path id="path1" fill="none" stroke="#efebe3" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M 18 6 L 6 18"/>
<path id="path2" fill="none" stroke="#efebe3" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M 6 6 L 18 18"/>
</svg>

After

Width:  |  Height:  |  Size: 523 B

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated by Pixelmator Pro 3.3.8 -->
<svg width="101" height="100" viewBox="0 0 101 100" xmlns="http://www.w3.org/2000/svg">
<g id="Group-copy">
<path id="Path-copy-2" fill="none" stroke="#efebe3" stroke-width="8.777778" stroke-linecap="round" stroke-linejoin="round" d="M 11 41.722221 C 11 58.68964 24.754808 72.444443 41.722221 72.444443 C 58.68964 72.444443 72.444443 58.68964 72.444443 41.722221 C 72.444443 24.754807 58.68964 11 41.722221 11 C 24.754808 11 11 24.754807 11 41.722221"/>
<path id="Path-copy" fill="none" stroke="#efebe3" stroke-width="8.777778" stroke-linecap="round" stroke-linejoin="round" d="M 90 90 L 63.666668 63.666668"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 729 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.8 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated by Pixelmator Pro 3.3.8 -->
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path id="Path" fill="none" stroke="none" d="M 0 0 L 24 0 L 24 24 L 0 24 Z"/>
<path id="path1" fill="none" stroke="#140d0d" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M 4 6 L 20 6"/>
<path id="path2" fill="none" stroke="#140d0d" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M 4 12 L 20 12"/>
<path id="path3" fill="none" stroke="#140d0d" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M 4 18 L 20 18"/>
</svg>

After

Width:  |  Height:  |  Size: 658 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 648 KiB

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated by Pixelmator Pro 3.3.8 -->
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path id="Path" fill="none" stroke="none" d="M 0 0 L 24 0 L 24 24 L 0 24 Z"/>
<path id="path1" fill="#ea6010" stroke="none" d="M 17 3.34 C 21.1674 5.746208 23.030024 10.779379 21.433001 15.318825 C 19.835976 19.858273 15.232252 22.616514 10.476249 21.883377 C 5.720245 21.15024 2.160861 17.133654 2.005 12.324 L 2 12 L 2.005 11.676 C 2.118919 8.162982 4.068822 4.967705 7.140892 3.259882 C 10.212963 1.552061 13.95609 1.582479 17 3.34 Z M 15 14 L 9 14 L 8.883 14.007 C 8.37995 14.066836 8.001114 14.493402 8.001114 15 C 8.001114 15.506598 8.37995 15.933164 8.883 15.993 L 9 16 L 15 16 L 15.117 15.993 C 15.62005 15.933164 15.998886 15.506598 15.998886 15 C 15.998886 14.493402 15.62005 14.066836 15.117 14.007 L 15 14 Z M 9.01 9 L 8.883 9.007 C 8.37995 9.066836 8.001114 9.493402 8.001114 10 C 8.001114 10.506598 8.37995 10.933164 8.883 10.993 L 9 11 L 9.127 10.993 C 9.630051 10.933164 10.008885 10.506598 10.008885 10 C 10.008885 9.493402 9.630051 9.066836 9.127 9.007 L 9.01 9 Z M 15.01 9 L 14.883 9.007 C 14.37995 9.066836 14.001114 9.493402 14.001114 10 C 14.001114 10.506598 14.37995 10.933164 14.883 10.993 L 15 11 L 15.127 10.993 C 15.630051 10.933164 16.008886 10.506598 16.008886 10 C 16.008886 9.493402 15.630051 9.066836 15.127 9.007 L 15.01 9 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated by Pixelmator Pro 3.3.8 -->
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path id="Path" fill="none" stroke="none" d="M 0 0 L 24 0 L 24 24 L 0 24 Z"/>
<path id="path1" fill="#fb263a" stroke="none" d="M 17 3.34 C 21.1674 5.746208 23.030024 10.779379 21.433001 15.318825 C 19.835976 19.858273 15.232252 22.616514 10.476249 21.883377 C 5.720245 21.15024 2.160861 17.133654 2.005 12.324 L 2 12 L 2.005 11.676 C 2.118919 8.162982 4.068822 4.967705 7.140892 3.259882 C 10.212963 1.552061 13.95609 1.582479 17 3.34 Z M 15.57 13.502 C 13.250918 13.340779 10.940379 13.918414 8.97 15.152 C 8.501662 15.444711 8.359289 16.061663 8.652 16.530001 C 8.944711 16.998337 9.561663 17.140711 10.03 16.848 C 11.642129 15.838702 13.53257 15.366092 15.43 15.498 C 15.98118 15.53666 16.459339 15.121181 16.497999 14.57 C 16.536659 14.01882 16.12118 13.54066 15.57 13.502 Z M 9.01 9 L 8.883 9.007 C 8.37995 9.066836 8.001114 9.493402 8.001114 10 C 8.001114 10.506598 8.37995 10.933164 8.883 10.993 L 9 11 L 9.127 10.993 C 9.630051 10.933164 10.008885 10.506598 10.008885 10 C 10.008885 9.493402 9.630051 9.066836 9.127 9.007 L 9.01 9 Z M 15.01 9 L 14.883 9.007 C 14.37995 9.066836 14.001114 9.493402 14.001114 10 C 14.001114 10.506598 14.37995 10.933164 14.883 10.993 L 15 11 L 15.127 10.993 C 15.630051 10.933164 16.008886 10.506598 16.008886 10 C 16.008886 9.493402 15.630051 9.066836 15.127 9.007 L 15.01 9 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

View file

@ -0,0 +1,171 @@
export default class RecordPlayer {
//--------------------------
// constructor
//--------------------------
constructor() {
this.audio = null;
this.tracklist = "";
this.currentTrackIndex = -1;
this.trackListCount = 0;
this.playing = false;
this.controlText = document.querySelector(".control-text");
this.tapePlaylist = document.getElementById("playlist");
this.nextBtn = document.getElementById("control-next");
this.backBtn = document.getElementById("control-back");
this.progress = document.querySelector(".audio-progress");
this.setUpAudio();
}
setUpAudio() {
let self = this;
//create element
this.audio = document.createElement("audio");
this.audio.controls = false;
//set event listners
this.audio.addEventListener(
"timeupdate",
(e) => this.handleTimeUpdate(e),
false
);
this.audio.addEventListener("ended", () => self.control("next"), false);
this.nextBtn.addEventListener("click", () => {
self.control("next");
});
this.backBtn.addEventListener("click", () => {
self.control("back");
});
}
setTrackList(tracklist) {
this.tracklist = tracklist;
this.trackListCount = this.tracklist.length;
this.buildPlaylist(this.tracklist);
}
buildPlaylist(tracklist) {
//clear playlist
this.tapePlaylist.innerHTML = "";
//build playlist ui
for (var i = 0, length = tracklist.length; i < length; i++) {
let sleeve = document.createElement("div");
let select = document.createElement("button");
sleeve.className = "sleeve";
sleeve.id = "sleeve_" + i;
select.id = tracklist[i].file;
select.className = "selectBtn";
let recordTitle = document.createElement("label");
recordTitle.id = "title_" + i;
recordTitle.innerText = tracklist[i].title;
let recordAlbum = document.createElement("label");
recordAlbum.id = "album_" + i;
recordAlbum.innerText = tracklist[i].album;
let recordArtist = document.createElement("label");
recordArtist.id = "artist_" + i;
recordArtist.innerText = tracklist[i].artist;
sleeve.appendChild(select);
sleeve.appendChild(recordTitle);
sleeve.appendChild(recordAlbum);
sleeve.appendChild(recordArtist);
this.tapePlaylist.appendChild(sleeve);
select.addEventListener("click", (e) => this.handleButton(e), false);
}
}
playRecord(file) {
for (var i = 0, length = this.tracklist.length; i < length; i++) {
let sleeve = document.getElementById("sleeve_" + i);
let album = document.getElementById("album_" + i);
let artist = document.getElementById("artist_" + i);
//handle pause state
if (file == this.tracklist[i].file) {
//if index is same, play our pause
if (i === this.currentTrackIndex) {
if (this.playing) {
this.audio.pause();
sleeve.style.opacity = 0.5;
this.playing = false;
return;
} else {
console.log("play");
this.audio.play();
sleeve.style.opacity = 1;
this.playing = true;
return;
}
} else {
//if index is different play next track
this.currentTrackIndex = i;
this.controlText.innerText = this.tracklist[i].title;
sleeve.classList.add("playing");
sleeve.classList.remove("not-playing");
album.classList.add("label-playing");
album.classList.remove("label-notplaying");
artist.classList.add("label-playing");
artist.classList.remove("label-notplaying");
}
} else {
sleeve.classList.add("not-playing");
sleeve.classList.remove("playing");
album.classList.add("label-notplaying");
artist.classList.add("label-notplaying");
}
}
let record =
"assets/audio/tapes/" +
this.tracklist[this.currentTrackIndex].tape +
"/" +
this.tracklist[this.currentTrackIndex].file;
this.audio.src = record;
this.audio.volume = 0.5;
this.playing = true;
this.audio.play();
}
control(task) {
this.playing = false;
let fresh = "";
switch (task) {
case "next":
fresh = this.currentTrackIndex + 1;
if (fresh > this.tracklist.length - 1) fresh = 0;
break;
case "back":
fresh = this.currentTrackIndex - 1;
if (fresh < 0) fresh = this.tracklist.length - 1;
break;
}
this.playRecord(this.tracklist[fresh].file);
}
//event handlers
handleButton(e) {
e.stopPropagation();
e.preventDefault();
this.playRecord(e.target.id);
}
handleTimeUpdate(e) {
var s = parseInt(this.audio.currentTime % 60);
if (s < 10) {
s = "0" + s;
}
var m = parseInt((this.audio.currentTime / 60) % 60);
if (m < 10) {
m = "0" + m;
}
var currentProgress = this.audio.currentTime / this.audio.duration;
var visProgress = 350 * currentProgress;
this.progress.style.width = visProgress + "px";
}
}

9
assets/script/Start.js Normal file
View file

@ -0,0 +1,9 @@
import TapeDeck from "./TapeDeck.js";
document.addEventListener(
"DOMContentLoaded",
function () {
new TapeDeck();
},
false
);

74
assets/script/TapeDeck.js Normal file
View file

@ -0,0 +1,74 @@
import RecordPlayer from "./RecordPlayer.js";
export default class TapeDeck {
//--------------------------
// constructor
//--------------------------
constructor() {
let self = this;
this.rp = new RecordPlayer();
this.tapeSelect = document.querySelector(".tape-select");
this.tapeTracklist = document.querySelector(".tape-tracklist");
this.tapeCover = document.getElementById("tape-cover");
this.tapeTitle = document.getElementById("tape-title");
this.tapeControls = document.getElementById("tape-controls");
this.logo = document.querySelector(".the-logo");
this.logo.addEventListener("click", (e) => {
self.tapeSelect.classList.remove("back-left");
self.tapeSelect.classList.add("front");
self.tapeTracklist.classList.remove("front");
self.tapeTracklist.classList.add("back-right");
self.tapeControls.classList.add("control-closed");
self.tapeControls.classList.remove("control-open");
});
var request = new XMLHttpRequest();
request.open("GET", "api/tapes/list", true);
request.onload = () => {
if (request.status == 200) {
let response = JSON.parse(request["response"]);
//console.log(response);
} else {
let error = JSON.parse(request["response"]);
consolel.log();
}
};
request.send();
//make images buttons for playlist retrieval
var covers = document.querySelectorAll(".covers");
for (var i = 0, length = covers.length; i < length; i++) {
covers[i].addEventListener("click", (e) => this.handleCovers(e), false);
}
}
//event handlers
handleCovers(e) {
e.stopPropagation();
e.preventDefault();
var request = new XMLHttpRequest();
let self = this;
request.open("GET", "api/tapes/tracklist/" + e.target.id, true);
request.onload = () => {
if (request.status == 200) {
let response = JSON.parse(request["response"]);
//once playlist is loaded, flip to list mode
self.tapeSelect.classList.remove("front");
self.tapeSelect.classList.add("back-left");
self.tapeTracklist.classList.remove("back-right");
self.tapeTracklist.classList.add("front");
self.tapeCover.src = e.target.src;
self.tapeTitle.innerText = "VOL. " + response[0].tape;
//open tape controls
self.tapeControls.classList.remove("control-closed");
self.tapeControls.classList.add("control-open");
//set up player
self.rp.setTrackList(response);
} else {
let error = JSON.parse(request["response"]);
}
};
request.send();
}
}

File diff suppressed because it is too large Load diff

10
brain/Loader.php Normal file
View file

@ -0,0 +1,10 @@
<?php
spl_autoload_register(function ($className) {
$file = dirname(__DIR__) . "\\" . $className . ".php";
$file = str_replace("\\", DIRECTORY_SEPARATOR, $file);
//echo $file;
if (file_exists($file)) {
include $file;
}
});

View file

@ -0,0 +1,33 @@
<?php
namespace brain\controllers;
class APIController
{
protected $tapes;
public function __construct()
{
$this->tapes = new TapesAPI();
}
public function handleRoute($params)
{
if (isset($params[1])) {
//grap appropriate api class based on request params
switch ($params[1]) {
case "tapes":
//run the request
return $this->tapes->handleRequest($params);
break;
default:
break;
}
} else {
return json_encode([
"message" => "NO API Identifier provided",
"type" => "ERROR",
]);
}
}
}

View file

@ -0,0 +1,15 @@
<?php
namespace brain\controllers;
class IndexController
{
public function __construct()
{
}
public function start()
{
echo "got it";
}
}

View file

@ -0,0 +1,36 @@
<?php
namespace brain\controllers;
use brain\controllers\APIController;
class RouteController
{
protected $api;
public function __construct()
{
$this->api = new APIController();
}
public function start($request)
{
$request = ltrim($request, " / ");
$params = explode("/", $request);
if ($params[0] == "") {
require "brain/views/front.php";
} else {
switch ($params[0]) {
case "api":
//get api controller to handle route
$result = $this->api->handleRoute($params);
header("Content-Type: application/json; charset=utf-8");
echo $result;
break;
default:
http_response_code(404);
require "brain/views/404.php";
break;
}
}
}
}

View file

@ -0,0 +1,96 @@
<?php
namespace brain\controllers;
use Kiwilan\Audio\Audio;
class TapesAPI
{
private $tapesDir = "assets/audio/tapes";
protected $params;
public function __construct()
{
}
public function handleRequest($params)
{
if (isset($params[2])) {
switch ($params[2]) {
case "list":
return $this->getList();
break;
case "tracklist":
return $this->getTrackList($params[3]);
break;
default:
return json_encode([
"message" => "This method does not exist",
"type" => "ERROR",
]);
break;
}
} else {
return json_encode([
"message" => "This method does not exist",
"type" => "ERROR",
]);
}
}
public function getTrackList($id)
{
$folder = $this->tapesDir . "/" . urldecode($id);
$contents = scandir($folder);
$tracklist = [];
foreach ($contents as $key => $value) {
$path = realpath($folder . DIRECTORY_SEPARATOR . $value);
if (!is_dir($path) && $value != ".DS_Store") {
$item = explode("/", $path);
if ($item[9] != "cover.jpg") {
$tags = Audio::read($path);
//reading cover data is lil funky, so off for now
//$cover = $tags->getCover();
//$image = $cover->getContents();
$album = "";
if (empty($tags->getAlbum())) {
$album = "None";
} else {
$album = $tags->getAlbum();
}
array_push($tracklist, [
"title" => $tags->getTitle(),
"album" => $album,
"artist" => $tags->getArtist(),
"time" => $tags->getDuration(),
"file" => $item[9],
"tape" => $item[8],
]);
}
}
}
usort($tracklist, function ($a, $b) {
return strnatcasecmp($a["file"], $b["file"]);
});
return json_encode($tracklist);
}
public function getList($obj = false)
{
$current = scandir($this->tapesDir);
$tapeList = [];
foreach ($current as $key => $value) {
$path = realpath($this->tapesDir . DIRECTORY_SEPARATOR . $value);
if (!is_dir($path) && $value != ".DS_Store") {
$results[] = $path;
} elseif ($value != "." && $value != ".." && $value != ".DS_Store") {
$titles = explode("/", $path);
array_push($tapeList, ["path" => $path, "title" => $titles[8]]);
}
}
if (!$obj) {
return json_encode($tapeList);
} else {
return $tapeList;
}
}
}

18
brain/views/404.php Normal file
View file

@ -0,0 +1,18 @@
<?php
include "parts/top.php"; ?>
<body>
<main>
<article class="splash-box">
<img class="logo-splash" src="assets/images/global/logo-primary.png" />
<h1>Uh Oh</h1>
<p>
This ain't it. Go back!
</p>
</article>
</main>
<?php include "parts/bottom.php"; ?>

39
brain/views/front.php Normal file
View file

@ -0,0 +1,39 @@
<?php
use brain\controllers\TapesAPI;
$tapes = new TapesAPI();
$covers = $tapes->getList(true);
include "parts/top.php";
?>
<header>
<img class="the-logo" src="assets/images/global/logo-primary.png" />
<div class="audio-progress"></div>
</header>
<div id="tape-controls" class="control-closed">
<img id="control-back" class="tape-control-button" src='assets/images/global/btn_back.png' />
<label class="control-text">NOTHING PLAYING</label>
<img id="control-next" class="tape-control-button" src='assets/images/global/btn_forward.png' />
</div>
<main>
<article class="tape-select front">
<?php foreach ($covers as $cover) {
$title = $cover["title"]; ?>
<img id="<?php echo urlencode($title); ?>" class="covers" src="
<?php echo "/assets/audio/tapes/" . $title . "/cover.jpg"; ?>" />
<?php
//end for each loop
} ?>
</article>
<article class="tape-tracklist back-right">
<img id="tape-cover" src='' />
<h1 id="tape-title"></h1>
<section id="playlist"></section>
</article>
</main>
<?php include "parts/bottom.php"; ?>

View file

@ -0,0 +1,4 @@
<script type="module" src="/assets/script/Start.js"></script>
</body>
</html>

17
brain/views/parts/top.php Normal file
View file

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="theme-color" content="#03061e" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>
The Vicious Tapes
</title>
<link rel="stylesheet" type="text/css" href="assets/css/front/start.css?=sdfsdf">
</head>
<body>
<script>
0
</script>

5
composer.json Normal file
View file

@ -0,0 +1,5 @@
{
"require": {
"kiwilan/php-audio": "^4.0"
}
}

170
composer.lock generated Normal file
View file

@ -0,0 +1,170 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "462518448f6c07a1a14fd4cba92297f2",
"packages": [
{
"name": "james-heinrich/getid3",
"version": "v1.9.23",
"source": {
"type": "git",
"url": "https://github.com/JamesHeinrich/getID3.git",
"reference": "06c7482532ff2b3f9111b011d880ca6699c8542b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/JamesHeinrich/getID3/zipball/06c7482532ff2b3f9111b011d880ca6699c8542b",
"reference": "06c7482532ff2b3f9111b011d880ca6699c8542b",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"php-parallel-lint/php-parallel-lint": "^1.0"
},
"suggest": {
"ext-SimpleXML": "SimpleXML extension is required to analyze RIFF/WAV/BWF audio files (also requires `ext-libxml`).",
"ext-com_dotnet": "COM extension is required when loading files larger than 2GB on Windows.",
"ext-ctype": "ctype extension is required when loading files larger than 2GB on 32-bit PHP (also on 64-bit PHP on Windows) or executing `getid3_lib::CopyTagsToComments`.",
"ext-dba": "DBA extension is required to use the DBA database as a cache storage.",
"ext-exif": "EXIF extension is required for graphic modules.",
"ext-iconv": "iconv extension is required to work with different character sets (when `ext-mbstring` is not available).",
"ext-json": "JSON extension is required to analyze Apple Quicktime videos.",
"ext-libxml": "libxml extension is required to analyze RIFF/WAV/BWF audio files.",
"ext-mbstring": "mbstring extension is required to work with different character sets.",
"ext-mysql": "MySQL extension is required to use the MySQL database as a cache storage (deprecated in PHP 5.5, removed in PHP >= 7.0, use `ext-mysqli` instead).",
"ext-mysqli": "MySQLi extension is required to use the MySQL database as a cache storage.",
"ext-rar": "RAR extension is required for RAR archive module.",
"ext-sqlite3": "SQLite3 extension is required to use the SQLite3 database as a cache storage.",
"ext-xml": "XML extension is required for graphic modules to analyze the XML metadata.",
"ext-zlib": "Zlib extension is required for archive modules and compressed metadata."
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.9.x-dev"
}
},
"autoload": {
"classmap": [
"getid3/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"GPL-1.0-or-later",
"LGPL-3.0-only",
"MPL-2.0"
],
"description": "PHP script that extracts useful information from popular multimedia file formats",
"homepage": "https://www.getid3.org/",
"keywords": [
"codecs",
"php",
"tags"
],
"support": {
"issues": "https://github.com/JamesHeinrich/getID3/issues",
"source": "https://github.com/JamesHeinrich/getID3/tree/v1.9.23"
},
"time": "2023-10-19T13:18:49+00:00"
},
{
"name": "kiwilan/php-audio",
"version": "4.0.01",
"source": {
"type": "git",
"url": "https://github.com/kiwilan/php-audio.git",
"reference": "028842cace360e8ba489df42ef24ebabb43a9c23"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/kiwilan/php-audio/zipball/028842cace360e8ba489df42ef24ebabb43a9c23",
"reference": "028842cace360e8ba489df42ef24ebabb43a9c23",
"shasum": ""
},
"require": {
"james-heinrich/getid3": "^v1.9.22",
"php": "^8.1"
},
"require-dev": {
"laravel/pint": "^1.2",
"pestphp/pest": "^2.0",
"phpstan/phpstan": "^1.12",
"spatie/ray": "^1.28"
},
"type": "library",
"autoload": {
"psr-4": {
"Kiwilan\\Audio\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ewilan Rivière",
"email": "ewilan.riviere@gmail.com",
"role": "Developer"
}
],
"description": "PHP package to parse and update audio files metadata, with `JamesHeinrich/getID3`.",
"homepage": "https://github.com/kiwilan/php-audio",
"keywords": [
"aif",
"aifc",
"aiff",
"alac",
"audio",
"audiobook",
"flac",
"id3",
"id3v1",
"id3v2",
"m4a",
"m4b",
"m4v",
"mka",
"mkv",
"mp3",
"mp4",
"music",
"ogg",
"opus",
"php",
"spx",
"tta",
"wav",
"webm",
"wma",
"wv"
],
"support": {
"issues": "https://github.com/kiwilan/php-audio/issues",
"source": "https://github.com/kiwilan/php-audio/tree/v4.0.01"
},
"funding": [
{
"url": "https://github.com/kiwilan",
"type": "github"
}
],
"time": "2024-10-03T16:57:29+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"plugin-api-version": "2.3.0"
}

24
index.php Normal file
View file

@ -0,0 +1,24 @@
<?php
// Load all the classes we need
require __DIR__ . "/brain/Loader.php";
require __DIR__ . "/vendor/autoload.php";
use brain\controllers\RouteController;
// Capture URI
$request = parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH);
// Strip leading /
//$request = ltrim($request, " / ");
$route = new RouteController();
// Match route and dispatch
try {
$route->start($request);
} catch (Exception $e) {
// No route found
http_response_code(404);
require __DIR__ . "/src/views/404.php";
}