Added search function using YT data API. Fixed slider and scrollbar on  web kit. Minor changes
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				Gitea/YTDJ/pipeline/head This commit looks good
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	Gitea/YTDJ/pipeline/head This commit looks good
				
			This commit is contained in:
		@@ -6,12 +6,15 @@ It's a simple way to play music from Youtube and smoothly fade between tracks th
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## What's next?
 | 
					## What's next?
 | 
				
			||||||
### Maybe one day
 | 
					### Maybe one day
 | 
				
			||||||
- Search videos straight from the app (needs API key and calls)
 | 
					- ~~Search videos straight from the app (needs API key and calls)~~
 | 
				
			||||||
- Compatibility with Bandcamp music (not sure if it can be done without too much hacks)
 | 
					- Compatibility with Bandcamp music (not sure if it can be done without too much hacks)
 | 
				
			||||||
 | 
					- A playlist of to-be-played tracks that can be added manually ("add url") or through the search
 | 
				
			||||||
 | 
					- A history of played tracks?
 | 
				
			||||||
### Should be done quickly
 | 
					### Should be done quickly
 | 
				
			||||||
- Clean code (especially old P5JS)
 | 
					- Clean code (especially old P5JS)
 | 
				
			||||||
- Sanitize it (naming, organization, comments...)
 | 
					- Sanitize it (naming, organization, comments...)
 | 
				
			||||||
- Add current tracks/playlists as hashes in the URL so we can share track combinations
 | 
					- Add current tracks/playlists as hashes in the URL so we can share track combinations
 | 
				
			||||||
 | 
					- Better indication of the video current status (playing or paused),maybe using `outline` on the iframe, or changing the `box-shadow color`?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## External resources and inspiration
 | 
					## External resources and inspiration
 | 
				
			||||||
### Inspiration
 | 
					### Inspiration
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										180
									
								
								css/main.css
									
									
									
									
									
								
							
							
						
						
									
										180
									
								
								css/main.css
									
									
									
									
									
								
							@@ -1,5 +1,5 @@
 | 
				
			|||||||
:root {
 | 
					:root {
 | 
				
			||||||
  --bg-color: #223;
 | 
					  --bg-color: 34, 34, 51;  /* #223 */
 | 
				
			||||||
  --text-color: #eee;
 | 
					  --text-color: #eee;
 | 
				
			||||||
  --text-color-light: #bbb;
 | 
					  --text-color-light: #bbb;
 | 
				
			||||||
  --accent-color-1: #ff91d8;
 | 
					  --accent-color-1: #ff91d8;
 | 
				
			||||||
@@ -9,7 +9,6 @@
 | 
				
			|||||||
  --crossfader-thumb-width: 30px;
 | 
					  --crossfader-thumb-width: 30px;
 | 
				
			||||||
  --crossfader-thumb-height: 60px;
 | 
					  --crossfader-thumb-height: 60px;
 | 
				
			||||||
  --crossfader-thumb-radius: 15px;
 | 
					  --crossfader-thumb-radius: 15px;
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@font-face {
 | 
					@font-face {
 | 
				
			||||||
@@ -79,6 +78,11 @@ textarea {
 | 
				
			|||||||
  resize: vertical;
 | 
					  resize: vertical;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					a, a:visited {
 | 
				
			||||||
 | 
					  color: inherit;
 | 
				
			||||||
 | 
					  text-decoration: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#bg {
 | 
					#bg {
 | 
				
			||||||
  z-index: -2;
 | 
					  z-index: -2;
 | 
				
			||||||
  overflow: hidden;
 | 
					  overflow: hidden;
 | 
				
			||||||
@@ -105,8 +109,7 @@ textarea {
 | 
				
			|||||||
#players, #search-area {
 | 
					#players, #search-area {
 | 
				
			||||||
  display: flex;
 | 
					  display: flex;
 | 
				
			||||||
  justify-content: center;
 | 
					  justify-content: center;
 | 
				
			||||||
  padding-bottom: 2em;
 | 
					  /* gap: 15px; */
 | 
				
			||||||
  gap: 15px;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.hidden {
 | 
					.hidden {
 | 
				
			||||||
@@ -142,15 +145,20 @@ iframe {
 | 
				
			|||||||
  /* right: 0; */
 | 
					  /* right: 0; */
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.load-button {
 | 
					input[type=button], button {
 | 
				
			||||||
  /* flex-grow: 2; */
 | 
					 | 
				
			||||||
   cursor: pointer;
 | 
					   cursor: pointer;
 | 
				
			||||||
   border: none;
 | 
					   border: none;
 | 
				
			||||||
   background-color: var(--accent-color-2);
 | 
					   background-color: var(--accent-color-2);
 | 
				
			||||||
  color: var(--bg-color);
 | 
					   color: rgb(var(--bg-color));
 | 
				
			||||||
  font-weight: 900;
 | 
					 | 
				
			||||||
   border-radius: 5px;
 | 
					   border-radius: 5px;
 | 
				
			||||||
  /* padding: 2em; */
 | 
					   font-weight: 900;
 | 
				
			||||||
 | 
					   transition: transform 0.2s ease;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					input[type=button]:hover, button:hover {
 | 
				
			||||||
 | 
					   transform: scale(1.1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.load-button {
 | 
				
			||||||
  width: 50%;
 | 
					  width: 50%;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -244,6 +252,8 @@ input[type=range]:focus {
 | 
				
			|||||||
input[type=range]::-webkit-slider-runnable-track {
 | 
					input[type=range]::-webkit-slider-runnable-track {
 | 
				
			||||||
  background: var(--accent-color-1);
 | 
					  background: var(--accent-color-1);
 | 
				
			||||||
  border-radius: 25px;
 | 
					  border-radius: 25px;
 | 
				
			||||||
 | 
					  margin-bottom: 0.5em;
 | 
				
			||||||
 | 
					  height: 4px;
 | 
				
			||||||
  width: 100%;
 | 
					  width: 100%;
 | 
				
			||||||
  cursor: pointer;
 | 
					  cursor: pointer;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -251,12 +261,13 @@ input[type=range]::-webkit-slider-thumb {
 | 
				
			|||||||
  background: var(--accent-color-2);
 | 
					  background: var(--accent-color-2);
 | 
				
			||||||
  border: solid var(--accent-color-1-light);
 | 
					  border: solid var(--accent-color-1-light);
 | 
				
			||||||
  border-width: 0px;
 | 
					  border-width: 0px;
 | 
				
			||||||
 | 
					  margin-top: -0.4em;
 | 
				
			||||||
 | 
					  width: 1em;
 | 
				
			||||||
 | 
					  height: 1em;
 | 
				
			||||||
 | 
					  border-radius: 1em;
 | 
				
			||||||
  cursor: pointer;
 | 
					  cursor: pointer;
 | 
				
			||||||
  -webkit-appearance: none;
 | 
					  -webkit-appearance: none;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
input[type=range]:focus::-webkit-slider-runnable-track {
 | 
					 | 
				
			||||||
  background: var(--accent-color-1-light);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
input[type=range]::-moz-range-track {
 | 
					input[type=range]::-moz-range-track {
 | 
				
			||||||
  background: var(--accent-color-1);
 | 
					  background: var(--accent-color-1);
 | 
				
			||||||
  width: 100%;
 | 
					  width: 100%;
 | 
				
			||||||
@@ -265,39 +276,10 @@ input[type=range]::-moz-range-track {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
input[type=range]::-moz-range-thumb {
 | 
					input[type=range]::-moz-range-thumb {
 | 
				
			||||||
  background: var(--accent-color-2);
 | 
					  background: var(--accent-color-2);
 | 
				
			||||||
  /* border: solid var(--accent-color-1-light); */
 | 
					 | 
				
			||||||
  cursor: pointer;
 | 
					  cursor: pointer;
 | 
				
			||||||
  border-width: 0px;
 | 
					  border-width: 0px;
 | 
				
			||||||
  border-radius: var(--crossfader-thumb-radius);
 | 
					  border-radius: var(--crossfader-thumb-radius);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
input[type=range]::-ms-track {
 | 
					 | 
				
			||||||
  background: transparent;
 | 
					 | 
				
			||||||
  border-color: transparent;
 | 
					 | 
				
			||||||
  color: transparent;
 | 
					 | 
				
			||||||
  width: 100%;
 | 
					 | 
				
			||||||
  cursor: pointer;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
input[type=range]::-ms-fill-lower {
 | 
					 | 
				
			||||||
  background: var(--accent-color-1);
 | 
					 | 
				
			||||||
  border-radius: 25px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
input[type=range]::-ms-fill-upper {
 | 
					 | 
				
			||||||
  background: var(--accent-color-1);
 | 
					 | 
				
			||||||
  border-radius: 25px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
input[type=range]::-ms-thumb {
 | 
					 | 
				
			||||||
  background: var(--accent-color-2);
 | 
					 | 
				
			||||||
  /* border: solid var(--accent-color-1-light); */
 | 
					 | 
				
			||||||
  cursor: pointer;
 | 
					 | 
				
			||||||
  margin-top: 0px;
 | 
					 | 
				
			||||||
  /*Needed to keep the Edge thumb centred*/
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
input[type=range]:focus::-ms-fill-lower {
 | 
					 | 
				
			||||||
  background: var(--accent-color-1);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
input[type=range]:focus::-ms-fill-upper {
 | 
					 | 
				
			||||||
  background: var(--accent-color-1-light);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*------------------------*/
 | 
					/*------------------------*/
 | 
				
			||||||
input[type=range]#crossfader::-webkit-slider-runnable-track {
 | 
					input[type=range]#crossfader::-webkit-slider-runnable-track {
 | 
				
			||||||
@@ -307,12 +289,11 @@ input[type=range]#crossfader::-webkit-slider-thumb {
 | 
				
			|||||||
  margin-top: -20.65px;
 | 
					  margin-top: -20.65px;
 | 
				
			||||||
  width: var(--crossfader-thumb-width);
 | 
					  width: var(--crossfader-thumb-width);
 | 
				
			||||||
  height: var(--crossfader-thumb-height);
 | 
					  height: var(--crossfader-thumb-height);
 | 
				
			||||||
  /* border-width: 5px;
 | 
					  border-radius: var(--crossfader-thumb-radius);
 | 
				
			||||||
  border-radius: 12px; */
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
input[type=range]#crossfader::-moz-range-track {
 | 
					input[type=range]#crossfader::-moz-range-track {
 | 
				
			||||||
  /* border-radius: 25px; */
 | 
					  border-radius: var(--crossfader-thumb-radius);
 | 
				
			||||||
  width: 100%;
 | 
					  width: 100%;
 | 
				
			||||||
  height: 13.3px;
 | 
					  height: 13.3px;
 | 
				
			||||||
  cursor: pointer;
 | 
					  cursor: pointer;
 | 
				
			||||||
@@ -320,39 +301,100 @@ input[type=range]#crossfader::-moz-range-track {
 | 
				
			|||||||
input[type=range]#crossfader::-moz-range-thumb {
 | 
					input[type=range]#crossfader::-moz-range-thumb {
 | 
				
			||||||
  width: var(--crossfader-thumb-width);
 | 
					  width: var(--crossfader-thumb-width);
 | 
				
			||||||
  height: var(--crossfader-thumb-height);
 | 
					  height: var(--crossfader-thumb-height);
 | 
				
			||||||
  /* border-width: 5px; */
 | 
					  border-radius: var(--crossfader-thumb-radius);
 | 
				
			||||||
  /* border-radius: 12px; */
 | 
					 | 
				
			||||||
  cursor: pointer;
 | 
					  cursor: pointer;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
input[type=range]#crossfader::-ms-track {
 | 
					
 | 
				
			||||||
  /* border-width: 18.75px 0; */
 | 
					.search-wrapper {
 | 
				
			||||||
  height: 13.3px;
 | 
					   /* margin-bottom: 2em; */
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
input[type=range]#crossfader::-ms-fill-lower {
 | 
					.search-bar-wrapper {
 | 
				
			||||||
  /* border-width: 2.3px;
 | 
					   display: flex;
 | 
				
			||||||
  border-radius: 50px; */
 | 
					   justify-content: center;
 | 
				
			||||||
}
 | 
					   align-items: center;
 | 
				
			||||||
input[type=range]#crossfader::-ms-fill-upper {
 | 
					   height: 2em;
 | 
				
			||||||
  /* border-radius: 50px; */
 | 
					   margin-bottom: 1em;
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
input[type=range]#crossfader::-ms-thumb {
 | 
					 | 
				
			||||||
  width: var(--crossfader-thumb-width);
 | 
					 | 
				
			||||||
  height: var(--crossfader-thumb-height);
 | 
					 | 
				
			||||||
  /* border-width: 5px;
 | 
					 | 
				
			||||||
  border-radius: 12px; */
 | 
					 | 
				
			||||||
  cursor: pointer;
 | 
					 | 
				
			||||||
  margin-top: 0px;
 | 
					 | 
				
			||||||
  /*Needed to keep the Edge thumb centred*/
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#search-bar {
 | 
				
			||||||
 | 
					   display: flex;
 | 
				
			||||||
 | 
					   column-gap: 1em;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#search-bar input, #search-bar button {
 | 
				
			||||||
 | 
					   height: 2em;;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#search-button {
 | 
				
			||||||
 | 
					   padding: 0.2em 1em;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#search-results {
 | 
				
			||||||
 | 
					   display: flex;
 | 
				
			||||||
 | 
					   overflow: auto;
 | 
				
			||||||
 | 
					   width: 95vw;
 | 
				
			||||||
 | 
					   /* flex-direction: column; */
 | 
				
			||||||
 | 
					   column-gap: 1em;
 | 
				
			||||||
 | 
					   /* padding-bottom: 1em; */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   scrollbar-width: thin;
 | 
				
			||||||
 | 
					   scrollbar-color: rgba(255,255,255,0.8) rgba(0,0,0,0);
 | 
				
			||||||
 | 
					   border-radius: 6px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#search-results::-webkit-scrollbar {
 | 
				
			||||||
 | 
					   height: 9px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#search-results::-webkit-scrollbar-track {
 | 
				
			||||||
 | 
					   background: rgba(0,0,0,0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#search-results::-webkit-scrollbar-thumb {
 | 
				
			||||||
 | 
					   background-color: rgba(255,255,255,0.8);
 | 
				
			||||||
 | 
					   width: 9px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.search-item {
 | 
				
			||||||
 | 
					   display: flex;
 | 
				
			||||||
 | 
					   justify-content: space-between;
 | 
				
			||||||
 | 
					   align-items: center;
 | 
				
			||||||
 | 
					   flex-direction: column;
 | 
				
			||||||
 | 
					   position: relative;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.search-item-info {
 | 
				
			||||||
 | 
					   position: relative;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.search-item-title {
 | 
				
			||||||
 | 
					   position: absolute;
 | 
				
			||||||
 | 
					   top: 0;
 | 
				
			||||||
 | 
					   margin: 0.5em;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.search-item-thumbnail img {
 | 
				
			||||||
 | 
					   /* width: 80%; */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.search-item-title span {
 | 
				
			||||||
 | 
					   display: inline;
 | 
				
			||||||
 | 
					   background-color: rgba(var(--bg-color), 0.8);
 | 
				
			||||||
 | 
					   padding: 0.3em 0;
 | 
				
			||||||
 | 
					   line-height: 1.8em;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.search-item-controls {
 | 
				
			||||||
 | 
					   display: flex;
 | 
				
			||||||
 | 
					   /* justify-content: center; */
 | 
				
			||||||
 | 
					   column-gap: 1em;
 | 
				
			||||||
 | 
					   margin: 0.5em;
 | 
				
			||||||
 | 
					   position: absolute;
 | 
				
			||||||
 | 
					   bottom: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.load-to-A, .load-to-B {
 | 
				
			||||||
 | 
					   padding: 0.5em;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
.footer {
 | 
					.footer {
 | 
				
			||||||
  font-weight: 100;
 | 
					  font-weight: 100;
 | 
				
			||||||
  padding-top: 2em;
 | 
					  /* padding-top: 2em; */
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
.footer a, .footer a:visited {
 | 
					 | 
				
			||||||
  color: var(--text-color);
 | 
					 | 
				
			||||||
  text-decoration: none;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.footer span {
 | 
					.footer span {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										33
									
								
								index.html
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								index.html
									
									
									
									
									
								
							@@ -84,24 +84,53 @@
 | 
				
			|||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="search-wrapper">
 | 
				
			||||||
 | 
					      <div class="search-bar-wrapper">
 | 
				
			||||||
 | 
					         <form id="search-bar">
 | 
				
			||||||
 | 
					           <input id='search-query' type="search" minlength="4" maxlength="512" placeholder="Search for Youtube videos">
 | 
				
			||||||
 | 
					           <button id='search-button' type="submit">Search</button>
 | 
				
			||||||
 | 
					        </form>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       <div id="search-results">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <div class="search-item" data-id="">
 | 
				
			||||||
 | 
					             <div class="search-item-info">
 | 
				
			||||||
 | 
					                <div class="search-item-thumbnail">
 | 
				
			||||||
 | 
					                   <img src="" alt="">
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					                <div class="search-item-title">
 | 
				
			||||||
 | 
					                   <a href="#" rel="noreferrer" target="_blank"><span>Titre vidéo</span></a>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					             </div>
 | 
				
			||||||
 | 
					             <div class="search-item-controls">
 | 
				
			||||||
 | 
					                <input type="button" class="load-to-A" value="Load to desk A">
 | 
				
			||||||
 | 
					                <input type="button" class="load-to-B" value="Load to desk B">
 | 
				
			||||||
 | 
					             </div>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <h1>🔊 Mix like a pro youtube DJ! 🎧</h1>
 | 
					    <h1>🔊 Mix like a pro youtube DJ! 🎧</h1>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div class="footer">
 | 
					    <div class="footer">
 | 
				
			||||||
      <p><span id='shooting-stars-enable'></span> <span class="spacer"></span>
 | 
					      <p><span id='shooting-stars-enable'></span> <span class="spacer"></span>
 | 
				
			||||||
        <a href="https://tflcl.xyz" target="_blank" >💜 Made by tflcl.xyz 💜</a>
 | 
					        <a href="https://tflcl.xyz" target="_blank" >💜 Made by tflcl.xyz 💜</a>
 | 
				
			||||||
        <span class="spacer"></span>
 | 
					        <span class="spacer"></span>
 | 
				
			||||||
        <a href="#" id="contact-me">💌 Contact me 💌</a>
 | 
					        <a href="#" id="contact-me">💌 Contact me 💌</a>
 | 
				
			||||||
        <span class="spacer"></span>
 | 
					        <span class="spacer"></span>
 | 
				
			||||||
        <a href="https://git.tflcl.xyz/tfl/YTDJ">🧩 Source code 🧩</a>
 | 
					        <a href="https://git.tflcl.xyz/tfl/YTDJ">🧩 More info / Source code 🧩</a>
 | 
				
			||||||
      </p>
 | 
					      </p>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <!-- REMOVE THIS LINE (Some light analytics to know how people use this website) -->
 | 
					 | 
				
			||||||
  <script async defer data-website-id="c073e27d-91e4-47fa-bd38-578b7fe727eb" src="https://stats.tflcl.xyz/sucre.js"></script>
 | 
					  <script async defer data-website-id="c073e27d-91e4-47fa-bd38-578b7fe727eb" src="https://stats.tflcl.xyz/sucre.js"></script>
 | 
				
			||||||
  <!-- Background was first made using P5JS -->
 | 
					  <!-- Background was first made using P5JS -->
 | 
				
			||||||
  <!-- <script src="/js/vendor/p5.js"></script>
 | 
					  <!-- <script src="/js/vendor/p5.js"></script>
 | 
				
			||||||
  <script src="/js/vendor/p5.svg.js"></script>
 | 
					  <script src="/js/vendor/p5.svg.js"></script>
 | 
				
			||||||
  <script src="/js/sketch.js"></script> -->
 | 
					  <script src="/js/sketch.js"></script> -->
 | 
				
			||||||
 | 
					  <script src="https://apis.google.com/js/api.js"></script>
 | 
				
			||||||
  <script src="/js/main.js"></script>
 | 
					  <script src="/js/main.js"></script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										107
									
								
								js/main.js
									
									
									
									
									
								
							
							
						
						
									
										107
									
								
								js/main.js
									
									
									
									
									
								
							@@ -116,6 +116,10 @@ class player {
 | 
				
			|||||||
    this.player.loadVideoById(trackID);
 | 
					    this.player.loadVideoById(trackID);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  cue(trackID) {
 | 
				
			||||||
 | 
					    this.player.cueVideoById(trackID);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  loadPlaylist(playlistID) {
 | 
					  loadPlaylist(playlistID) {
 | 
				
			||||||
    //First element should be the playlist ID, second element the index of the video to play
 | 
					    //First element should be the playlist ID, second element the index of the video to play
 | 
				
			||||||
    let list = playlistID[0];
 | 
					    let list = playlistID[0];
 | 
				
			||||||
@@ -201,9 +205,9 @@ function get_playlist_id(url) {
 | 
				
			|||||||
    let regPlaylist = /[?&]list=([^#\&\?]+)/;
 | 
					    let regPlaylist = /[?&]list=([^#\&\?]+)/;
 | 
				
			||||||
    let regIndex = /[?&]index=([^#]+)/;
 | 
					    let regIndex = /[?&]index=([^#]+)/;
 | 
				
			||||||
    let match = url.match(regPlaylist);
 | 
					    let match = url.match(regPlaylist);
 | 
				
			||||||
    console.log('match ' + match);
 | 
					    // console.log('match ' + match);
 | 
				
			||||||
    let matchIndex = url.match(regIndex);
 | 
					    let matchIndex = url.match(regIndex);
 | 
				
			||||||
    console.log('matchindex ' + matchIndex);
 | 
					    // console.log('matchindex ' + matchIndex);
 | 
				
			||||||
    // console.log('regexp ' + match.match(/=LL([^#\&\?]*)/));
 | 
					    // console.log('regexp ' + match.match(/=LL([^#\&\?]*)/));
 | 
				
			||||||
    let index = 0;
 | 
					    let index = 0;
 | 
				
			||||||
    if (matchIndex != null) {
 | 
					    if (matchIndex != null) {
 | 
				
			||||||
@@ -313,8 +317,6 @@ function newShootingStar() {
 | 
				
			|||||||
  document.documentElement.style.setProperty('--shooting-star-angle', angle + "deg");
 | 
					  document.documentElement.style.setProperty('--shooting-star-angle', angle + "deg");
 | 
				
			||||||
  document.documentElement.style.setProperty('--shooting-star-direction', direction);
 | 
					  document.documentElement.style.setProperty('--shooting-star-direction', direction);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  shootingStarWrapper.appendChild(shootingStar);
 | 
					  shootingStarWrapper.appendChild(shootingStar);
 | 
				
			||||||
  shootingStar.classList.add('shooting-star');
 | 
					  shootingStar.classList.add('shooting-star');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -346,8 +348,6 @@ document.getElementById('shooting-stars-enable').addEventListener('click', () =>
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Enable/disable shooting stars (with P5JS background)
 | 
					// Enable/disable shooting stars (with P5JS background)
 | 
				
			||||||
// if (typeof processingSketch !== 'undefined') {
 | 
					// if (typeof processingSketch !== 'undefined') {
 | 
				
			||||||
//   let separatorSpan = document.createElement('span');
 | 
					//   let separatorSpan = document.createElement('span');
 | 
				
			||||||
@@ -371,7 +371,6 @@ document.getElementById('shooting-stars-enable').addEventListener('click', () =>
 | 
				
			|||||||
- EMAIL OBFUSCATION - found here http://www.grall.name/posts/1/antiSpam-emailAddressObfuscation.html
 | 
					- EMAIL OBFUSCATION - found here http://www.grall.name/posts/1/antiSpam-emailAddressObfuscation.html
 | 
				
			||||||
-------------------------------------------------------*/
 | 
					-------------------------------------------------------*/
 | 
				
			||||||
document.getElementById('contact-me').addEventListener('click', (e) => {
 | 
					document.getElementById('contact-me').addEventListener('click', (e) => {
 | 
				
			||||||
  console.log('okay');
 | 
					 | 
				
			||||||
  var y = decode("pbagnpg@gsypy.klm"); //https://rot13.com/
 | 
					  var y = decode("pbagnpg@gsypy.klm"); //https://rot13.com/
 | 
				
			||||||
  e.target.setAttribute("href", "mailto:" + y);
 | 
					  e.target.setAttribute("href", "mailto:" + y);
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
@@ -383,3 +382,97 @@ function decode(a) {
 | 
				
			|||||||
    return String.fromCharCode((c <= "Z" ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26);
 | 
					    return String.fromCharCode((c <= "Z" ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26);
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					SEARCH WITH YOUTUBE API
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					let lastSearchQuery;
 | 
				
			||||||
 | 
					let results;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					gapi.load("client", loadClient);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// https://developers.google.com/youtube/v3/docs/search/list
 | 
				
			||||||
 | 
					function loadClient() {
 | 
				
			||||||
 | 
					  gapi.client.setApiKey("AIzaSyCuz5tGc9oDxw6RZnpibakYFHzMvsd8bUs");
 | 
				
			||||||
 | 
					  return gapi.client.load("https://www.googleapis.com/discovery/v1/apis/youtube/v3/rest")
 | 
				
			||||||
 | 
					      .then(function() { console.log("GAPI client loaded for API"); },
 | 
				
			||||||
 | 
					            function(err) { console.error("Error loading GAPI client for API", err); });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function execute(query) {
 | 
				
			||||||
 | 
					   // Make sure the client is loaded before calling this method.
 | 
				
			||||||
 | 
					   return gapi.client.youtube.search.list({
 | 
				
			||||||
 | 
					      "part": [
 | 
				
			||||||
 | 
					         "snippet"
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      "maxResults": 15,
 | 
				
			||||||
 | 
					      "q": query,
 | 
				
			||||||
 | 
					      "type": [
 | 
				
			||||||
 | 
					         "video"
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      "fields": "items(id/videoId,snippet(title,thumbnails/medium))"
 | 
				
			||||||
 | 
					   })
 | 
				
			||||||
 | 
					   .then(function(response) {
 | 
				
			||||||
 | 
					      if (response.status == 200) {
 | 
				
			||||||
 | 
					         results = response.result;
 | 
				
			||||||
 | 
					         localStorage.setItem('sres', JSON.stringify(results));
 | 
				
			||||||
 | 
					         displaySearchResults(results);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      // Handle the results here (response.result has the parsed body).
 | 
				
			||||||
 | 
					      console.log("Response", response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   },
 | 
				
			||||||
 | 
					   function(err) {
 | 
				
			||||||
 | 
					      console.error("Execute error", err);
 | 
				
			||||||
 | 
					      alert("Whoops, something went wrong. \n       Maybe all of my daily Youtube Data API requests have been used. Try again later! \n Maybe it's something else. Try again later?");
 | 
				
			||||||
 | 
					   });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const searchForm = document.getElementById('search-bar');
 | 
				
			||||||
 | 
					const searchQueryObj = document.getElementById('search-query');
 | 
				
			||||||
 | 
					const searchButtonObj = document.getElementById('search-button');
 | 
				
			||||||
 | 
					const searchResultsObj = document.getElementById('search-results');
 | 
				
			||||||
 | 
					//When the page has loaded, store the hidden search-item class div as a template for future searchs
 | 
				
			||||||
 | 
					const searchResultItemObj = searchResultsObj.querySelector('.search-item').cloneNode(true);
 | 
				
			||||||
 | 
					searchResultsObj.querySelector('.search-item').remove();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					searchForm.addEventListener('submit', (e) => {
 | 
				
			||||||
 | 
					   e.preventDefault(); // We handle the form submit by ourselve
 | 
				
			||||||
 | 
					   if (searchQueryObj.value != lastSearchQuery) { // prevent useless requests
 | 
				
			||||||
 | 
					      console.log('Search for: ' + searchQueryObj.value);
 | 
				
			||||||
 | 
					      execute(searchQueryObj.value);
 | 
				
			||||||
 | 
					      lastSearchQuery = searchQueryObj.value;
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					   return false;
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function displaySearchResults(res) {
 | 
				
			||||||
 | 
					   // First we clean previous search results
 | 
				
			||||||
 | 
					   while (searchResultsObj.firstChild) {
 | 
				
			||||||
 | 
					      searchResultsObj.removeChild(searchResultsObj.firstChild);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   res.items.forEach((item) => {
 | 
				
			||||||
 | 
					      let itemElmt = searchResultItemObj.cloneNode(true);
 | 
				
			||||||
 | 
					      itemElmt.querySelector('.search-item-info img').setAttribute('src', item.snippet.thumbnails.medium.url);
 | 
				
			||||||
 | 
					      itemElmt.querySelector('.search-item-info span').innerHTML = item.snippet.title;
 | 
				
			||||||
 | 
					      itemElmt.querySelector('.search-item-info a').setAttribute('href', 'https://www.youtube.com/watch?v=' + item.id.videoId)
 | 
				
			||||||
 | 
					      itemElmt.dataset.id = item.id.videoId;
 | 
				
			||||||
 | 
					      itemElmt.querySelector('.load-to-A').addEventListener('click', () => {
 | 
				
			||||||
 | 
					         playerA.cue(item.id.videoId);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      itemElmt.querySelector('.load-to-B').addEventListener('click', () => {
 | 
				
			||||||
 | 
					         playerB.cue(item.id.videoId);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      console.log(itemElmt);
 | 
				
			||||||
 | 
					      searchResultsObj.appendChild(itemElmt);
 | 
				
			||||||
 | 
					   });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// For testing purpose
 | 
				
			||||||
 | 
					results = JSON.parse(localStorage.getItem('sres'));
 | 
				
			||||||
 | 
					displaySearchResults(results);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user