Add direct search on web page to add music

This commit is contained in:
Sebastien 2018-11-22 00:57:32 +02:00
parent 085680ebb3
commit a2fff0db98
6 changed files with 320 additions and 80 deletions

View File

@ -3,6 +3,7 @@ package net.Broken.Tools;
import net.Broken.DB.Entity.GuildPreferenceEntity; import net.Broken.DB.Entity.GuildPreferenceEntity;
import net.Broken.MainBot; import net.Broken.MainBot;
import net.Broken.audio.Youtube.SearchResult; import net.Broken.audio.Youtube.SearchResult;
import net.Broken.audio.Youtube.YoutubeTools;
import net.dv8tion.jda.core.EmbedBuilder; import net.dv8tion.jda.core.EmbedBuilder;
import net.dv8tion.jda.core.entities.Member; import net.dv8tion.jda.core.entities.Member;
import net.dv8tion.jda.core.entities.MessageEmbed; import net.dv8tion.jda.core.entities.MessageEmbed;
@ -129,6 +130,7 @@ public class EmbedMessageUtils {
.setColor(Color.CYAN) .setColor(Color.CYAN)
.setTitle(result.title) .setTitle(result.title)
.setImage(result.imageUrl) .setImage(result.imageUrl)
.addField("Duration: ", YoutubeTools.getInstance().ytTimeToString(result.duration), false)
.addField("URL:","https://www.youtube.com/watch?v="+result.id,false) .addField("URL:","https://www.youtube.com/watch?v="+result.id,false)
.addField("Chanel:", result.channelTittle, false); .addField("Chanel:", result.channelTittle, false);
return buildStandar(builder); return buildStandar(builder);

View File

@ -8,8 +8,9 @@ public class SearchResult {
public String channelId; public String channelId;
public String channelTittle; public String channelTittle;
public String imageUrl; public String imageUrl;
public String duration;
public SearchResult(com.google.api.services.youtube.model.SearchResult result){ public SearchResult(com.google.api.services.youtube.model.SearchResult result, String duration){
id = result.getId().getVideoId(); id = result.getId().getVideoId();
title = result.getSnippet().getTitle(); title = result.getSnippet().getTitle();
description = result.getSnippet().getDescription(); description = result.getSnippet().getDescription();
@ -17,5 +18,6 @@ public class SearchResult {
channelId = result.getSnippet().getChannelId(); channelId = result.getSnippet().getChannelId();
channelTittle = result.getSnippet().getChannelTitle(); channelTittle = result.getSnippet().getChannelTitle();
imageUrl = result.getSnippet().getThumbnails().getDefault().getUrl(); imageUrl = result.getSnippet().getThumbnails().getDefault().getUrl();
this.duration = duration;
} }
} }

View File

@ -5,6 +5,8 @@ import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.youtube.YouTube; import com.google.api.services.youtube.YouTube;
import com.google.api.services.youtube.model.SearchListResponse; import com.google.api.services.youtube.model.SearchListResponse;
import com.google.api.services.youtube.model.SearchResult; import com.google.api.services.youtube.model.SearchResult;
import com.google.api.services.youtube.model.Video;
import com.google.api.services.youtube.model.VideoListResponse;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@ -12,6 +14,8 @@ import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import static org.hibernate.engine.jdbc.Size.LobMultiplier.M;
public class YoutubeTools { public class YoutubeTools {
private Logger logger = LogManager.getLogger(); private Logger logger = LogManager.getLogger();
@ -88,13 +92,80 @@ public class YoutubeTools {
searchList.setOrder("relevance"); searchList.setOrder("relevance");
SearchListResponse response = searchList.execute(); SearchListResponse response = searchList.execute();
StringBuilder idString = new StringBuilder();
for(SearchResult item : response.getItems()){
idString.append(item.getId().getVideoId()).append(",");
}
HashMap<String, Video> videoHashMap = new HashMap<>();
YouTube.Videos.List video = youTube.videos().list("contentDetails");
video.setId(idString.toString());
video.setKey(apiKey);
VideoListResponse videoResponse = video.execute();
for(Video item : videoResponse.getItems()){
videoHashMap.put(item.getId(), item);
}
ArrayList<net.Broken.audio.Youtube.SearchResult> finalResult = new ArrayList<>(); ArrayList<net.Broken.audio.Youtube.SearchResult> finalResult = new ArrayList<>();
for(SearchResult item : response.getItems()){ for(SearchResult item : response.getItems()){
logger.debug(item.getSnippet().getTitle()); logger.debug(item.getSnippet().getTitle());
finalResult.add(new net.Broken.audio.Youtube.SearchResult(item)); finalResult.add(new net.Broken.audio.Youtube.SearchResult(item, videoHashMap.get(item.getId().getVideoId()).getContentDetails().getDuration()));
} }
return finalResult; return finalResult;
} }
public String ytTimeToString(String time){
int hours;
int minutes;
int seconds;
if(time.equals("PT0S"))
return ":red_circle: LIVE";
time = time.replace("PT","");
if(time.contains("H")) {
String matched = time.substring(0, time.indexOf("H")+1);
time = time.replace(matched,"");
hours = Integer.parseInt(matched.replace("H", ""));
}
else
hours = 0;
logger.debug(time);
if(time.contains("M")) {
String matched = time.substring(0, time.indexOf("M")+1);
time = time.replace(matched,"");
minutes = Integer.parseInt(matched.replace("M", ""));
}
else
minutes = 0;
logger.debug(time);
if(time.contains("S")) {
String matched = time.substring(0, time.indexOf("S")+1);
time = time.replace(matched,"");
seconds = Integer.parseInt(matched.replace("S", ""));
}
else
seconds = 0;
logger.debug(time);
String hoursStr = (hours < 10) ? "0" + hours : String.valueOf(hours);
String minutesStr = (minutes < 10) ? "0" + minutes : String.valueOf(minutes);
String secondsStr = (seconds < 10) ? "0" + seconds : String.valueOf(seconds);
if (hours > 0)
return hoursStr + ":" + minutesStr + ":" + secondsStr;
else
return minutesStr + ":" + secondsStr;
}
} }

View File

@ -8,3 +8,4 @@
.collapsible-body{ .collapsible-body{
padding: 0px; padding: 0px;
} }

View File

@ -15,7 +15,7 @@ var loadingFlag = false;
var guild; var guild;
$(document).ready(function () { $(document).ready(function () {
if (Cookies.get('guild') != undefined) { if (Cookies.get('guild') !== undefined) {
guild = Cookies.get('guild'); guild = Cookies.get('guild');
btn_play = $('#btn_play'); btn_play = $('#btn_play');
@ -28,7 +28,8 @@ $(document).ready(function () {
switchAutoFlow = $("#autoflow"); switchAutoFlow = $("#autoflow");
setInterval("getCurentMusic()", 1000); setInterval("getCurentMusic()", 1000);
$('#modalAdd').modal();
M.Modal.init($('#modalAdd').get(0));
$('#modal_current_info').modal(); $('#modal_current_info').modal();
@ -75,7 +76,7 @@ function getCurentMusic() {
$('#btn_info').addClass("determinate").removeClass("indeterminate"); $('#btn_info').addClass("determinate").removeClass("indeterminate");
} }
$('#music_progress').width("0%"); $('#music_progress').width("0%");
if (Cookies.get('token') != undefined) { if (Cookies.get('token') !== undefined) {
disableBtn(btn_stop); disableBtn(btn_stop);
disableBtn(btn_info); disableBtn(btn_info);
enableBtn(btn_add); enableBtn(btn_add);
@ -298,7 +299,7 @@ function updateControl(data) {
} }
$('#music_progress').width(percent + "%"); $('#music_progress').width(percent + "%");
if (Cookies.get('token') != undefined) { if (Cookies.get('token') !== undefined) {
enableBtn(btn_play); enableBtn(btn_play);
enableBtn(btn_stop); enableBtn(btn_stop);
enableBtn(btn_info); enableBtn(btn_info);
@ -327,7 +328,7 @@ function updateControl(data) {
function sendCommand(command) { function sendCommand(command) {
modal_loading.modal('open'); modal_loading.modal('open');
console.log(command); // console.log(command);
$.ajax({ $.ajax({
type: "POST", type: "POST",
dataType: 'json', dataType: 'json',
@ -343,13 +344,19 @@ function sendCommand(command) {
}).fail(function (data) { }).fail(function (data) {
console.log(data); console.log(data);
alert(data.responseJSON.Message);
modal_loading.modal('close'); modal_loading.modal('close');
if (data.responseJSON.error === "token") { if (data.responseJSON.error === "token") {
Cookies.remove('token'); Cookies.remove('token');
Cookies.remove('name'); Cookies.remove('name');
location.reload(); location.reload();
} }
else{
M.toast({
html: " <i class=\"material-icons\" style='margin-right: 10px'>warning</i> Command fail!",
classes: 'red',
displayLength: 99999999
});
}
}); });
} }
@ -358,18 +365,116 @@ function comparePlaylist(list1, list2) {
return false; return false;
} }
if (list1.length != list2.length) { if (list1.length !== list2.length) {
return false; return false;
} }
for (var i = 0; i++; i < list1.length) { for (var i = 0; i++; i < list1.length) {
if (list1[i].uri != list2[i].uri) if (list1[i].uri !== list2[i].uri)
return false return false
} }
return true; return true;
} }
function search() {
let query = $('#input_search').val();
let list = $("#search_result");
let load = $("#search_load");
disableBtn($('#btn_search'));
// list.addClass("hide");
list.removeClass("scale-in");
load.removeClass("hide");
load.addClass("scale-in");
$.get("/api/music/search?query=" + query, (data) => {
// console.log(data);
list.empty();
data.forEach((item)=>{
let html =
"<li class=\"collection-item avatar\">" +
" <img src=\""+item["imageUrl"]+"\" alt=\"\" class=\"\">" +
" <a class=\"title truncate\" href='https://youtube.com/watch?v="+item["id"]+"' target=\"_blank\"><b>"+item["title"]+"</b></a>" +
" <p class='truncate grey-text text-darken-1'>"+item["channelTittle"]+ " &#9553 "+ item["publishedAt"].substr(0, item["publishedAt"].indexOf('T'))+" <br>" + ytTimeToTime(item["duration"]) +
" </p>" +
" <a href=\"#!\" class=\"secondary-content btn waves-effect waves-light green add-btn-list scale-transition\" id='"+item["id"]+"'><i class=\"material-icons \">add_circle_outline</i></a>" +
" </div>" +
"</li>";
list.append(html)
});
$(".add-btn-list").click(addListClick);
// list.removeClass("hide");
load.removeClass("scale-in");
load.addClass("hide");
list.addClass("scale-in");
enableBtn($('#btn_search'));
});
}
function addListClick(event){
let button;
if(event.target.nodeName === "I"){
button = event.target.parentNode;
}
else
button = event.target;
button.classList.add("scale-out");
let command = {
command: "ADD",
url: button.id,
playlistLimit: $('#limit_range').val(),
onHead: !$('#bottom').is(':checked')
};
sendCommand(command);
}
function ytTimeToTime(duration) {
let hours;
let minutes;
let seconds;
if(duration === "PT0S")
return "&#x1F534 LIVE";
if(duration.includes("H"))
hours = parseInt(duration.match(/\d*H/)[0].replace("H",""), 10);
else
hours = 0;
if(duration.includes("M"))
minutes = parseInt(duration.match(/\d*M/)[0].replace("M",""), 10);
else
minutes = 0;
if(duration.includes("S"))
seconds = parseInt(duration.match(/\d*S/)[0].replace("S",""), 10);
else
seconds = 0;
hours = (hours < 10) ? "0" + hours : hours;
minutes = (minutes < 10) ? "0" + minutes : minutes;
seconds = (seconds < 10) ? "0" + seconds : seconds;
if (hours > 0)
return hours + ":" + minutes + ":" + seconds;
else
return minutes + ":" + seconds;
}
function msToTime(duration) { function msToTime(duration) {
var milliseconds = parseInt((duration % 1000) / 100) var milliseconds = parseInt((duration % 1000) / 100)
, seconds = parseInt((duration / 1000) % 60) , seconds = parseInt((duration / 1000) % 60)
@ -403,6 +508,8 @@ function listeners() {
}); });
$('#btn_search').click(search);
$('#btn_next').click(function () { $('#btn_next').click(function () {
sendCommand({command: "NEXT"}); sendCommand({command: "NEXT"});
}); });
@ -419,6 +526,26 @@ function listeners() {
} }
}); });
$('#input_search').on("input", function () {
if ($('#input_search').val() == "") {
disableBtn($('#btn_search'));
}
else {
enableBtn($('#btn_search'));
}
});
$('#add_btn').click(function () {
if ($('#input_search').val() == "") {
disableBtn($('#btn_search'));
}
else {
enableBtn($('#btn_search'));
}
});
$('#modalChanels').change(function () { $('#modalChanels').change(function () {
if ($('#btn_ok_channel').hasClass("disabled")) { if ($('#btn_ok_channel').hasClass("disabled")) {
$('#btn_ok_channel').removeClass("disabled"); $('#btn_ok_channel').removeClass("disabled");
@ -432,18 +559,6 @@ function listeners() {
sendCommand(command); sendCommand(command);
}); });
$('#btn_add').click(function () {
console.log(!$('#bottom').is(':checked'));
var command = {
command: "ADD",
url: $('#input_link').val(),
playlistLimit: $('#limit_range').val(),
onHead: !$('#bottom').is(':checked')
};
$('#input_link').val('');
sendCommand(command);
});
$('#btn_ok_channel').click(function () { $('#btn_ok_channel').click(function () {
var command = { var command = {
@ -458,7 +573,7 @@ function listeners() {
}); });
switchAutoFlow.click(function () { switchAutoFlow.click(function () {
console.log(switchAutoFlow.is(':checked')) // console.log(switchAutoFlow.is(':checked'));
if (switchAutoFlow.is(':checked')) { if (switchAutoFlow.is(':checked')) {
sendCommand({command: 'AUTOFLOWON'}) sendCommand({command: 'AUTOFLOWON'})
} }

View File

@ -10,10 +10,42 @@
<!-- CSS --> <!-- CSS -->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"/> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"/>
<link href="css/materialize.css" type="text/css" rel="stylesheet" media="screen,projection"/> <link href="/css/materialize.css" type="text/css" rel="stylesheet" media="screen,projection"/>
<link href="css/style.css" type="text/css" rel="stylesheet" media="screen,projection"/> <link href="/css/style.css" type="text/css" rel="stylesheet" media="screen,projection"/>
<link rel="manifest" href="/manifest.json"/> <link rel="manifest" href="/manifest.json"/>
<meta name="theme-color" content="#263238"/> <meta name="theme-color" content="#263238"/>
<style>
@media only screen and (max-width: 1200px) {
#modalAdd{
width: 95%;
}
}
@media only screen and (min-width: 1200px) {
#modalAdd{
width: 80%;
}
}
#modalAdd{
height: 85% !important;
max-height: 100% !important;
}
.avatar>img{
position: absolute;
width: 80px;
height: auto;
overflow: hidden;
left: 15px;
display: inline-block;
vertical-align: middle;
}
.collection-item.avatar{
padding-left: 105px !important;
padding-right: 75px;
}
</style>
</head> </head>
@ -89,60 +121,7 @@
<!-- Modal Trigger --> <!-- Modal Trigger -->
<a class="waves-effect waves-light btn modal-trigger green darken-4" id="add_btn" href="#modalAdd"><i class="material-icons">add_circle_outline</i></a> <a class="waves-effect waves-light btn modal-trigger green darken-4" id="add_btn" href="#modalAdd"><i class="material-icons">add_circle_outline</i></a>
<!-- Modal Structure -->
<div id="modalAdd" class="modal modal ">
<div class="modal-content" style="padding-bottom: 0px">
<div class="row" style="margin-bottom: 0px">
<h3 class="col l12 m12 s12"> Add Music</h3>
<form class="col l12 m12 s12">
<div class="row" style="margin-bottom: 0px">
<div class="input-field col l12 m12 s12" style="padding-left: 0px; padding-right: 0px">
<!--<i class="material-icons prefix">link</i>-->
<input id="input_link" type="text" class="validate"/>
<label for="input_link">Link</label>
</div>
</div>
<div class="row" style="margin-bottom: 0px">
<div class="col l12 m12 s12 center">
Playlist Limit
</div>
</div>
<div class="row" style="margin-bottom: 0px">
<p class="range-field">
<input type="range" id="limit_range" min="1" max="300" step="1" value="30" />
</p>
</div>
<div class="row" style="margin-bottom: 0px">
<div class="col l12 m12 s12 center">
Add on
</div>
</div>
<div class="row">
<div class="col l4 offset-l4 m4 offset-m4 s4 offset-s4 left-align ">
<p>
<label>
<input name="group1" type="radio" checked="checked" id="bottom"/>
<span>Bottom</span>
</label>
</p>
<p>
<label>
<input name="group1" type="radio" />
<span>Top</span>
</label>
</p>
</div>
</div>
</form>
</div>
</div>
<div class="modal-footer">
<a href="#!" class="modal-action modal-close waves-effect waves-green btn-flat">Cancel</a>
<a href="#!" id="btn_add" class="modal-action modal-close waves-effect waves-green btn-flat disabled">Add</a>
</div>
</div>
</div> </div>
<div class="col l3 m2 s2 center " style="padding-left: 0px"> <div class="col l3 m2 s2 center " style="padding-left: 0px">
<div class="row switch blue-grey-text text-darken-3" style="margin-bottom: 0px"> <div class="row switch blue-grey-text text-darken-3" style="margin-bottom: 0px">
@ -198,6 +177,74 @@
</div> </div>
<!--Add Modal-->
<div id="modalAdd" class="modal modal-fixed-footer ">
<div class="modal-content" style="padding-bottom: 0px">
<div class="row valign-wrapper">
<h3 class="col l12 m12 s12 center"> Add Music</h3>
</div>
<div class="row" style="margin-bottom: 0px">
<form class="col l12 m12 s12">
<div class="row" style="margin-bottom: 0">
<div class="input-field col offset-l1 l9 m10 s10" style="padding-left: 0px; padding-right: 0px">
<!--<i class="material-icons prefix">link</i>-->
<input id="input_search" type="text" class="validate"/>
<label for="input_search">Search</label>
</div>
<div class="input-field col l2 m2 s2" style="margin-top: 22px">
<button class="btn waves-effect waves-light green darken-4 white-text" id="btn_search"><i class="material-icons">search</i></button>
</div>
</div>
<div class="row">
<div class="col s12 m12 l12 center scale-transition scale-out hide" id="search_load" style="margin-top: 25px">
<div class="preloader-wrapper big active">
<div class="spinner-layer spinner-blue-only">
<div class="circle-clipper left">
<div class="circle"></div>
</div>
<div class="gap-patch">
<div class="circle"></div>
</div>
<div class="circle-clipper right">
<div class="circle"></div>
</div>
</div>
</div>
</div>
<ul class="collection col l12 m12 s12 scale-transition scale-out" id="search_result" style="padding: 0">
</ul>
</div>
</form>
</div>
</div>
<div class="modal-footer">
<span style="margin-right: 10px">
<label>
<input name="group1" type="radio" checked="checked" id="bottom"/>
<span>Bottom</span>
</label>
</span>
<span style="margin-right: 10px">
<label>
<input name="group1" type="radio" />
<span>Top</span>
</label>
</span>
<a href="#" class="modal-action modal-close waves-effect waves-green btn-flat">Close</a>
</div>
</div>
<!-- Playlist template--> <!-- Playlist template-->
<li id="playlist_template" style="visibility: hidden"> <li id="playlist_template" style="visibility: hidden">
<div class="collapsible-header"><i class="material-icons">drag_handle</i>@title</div> <div class="collapsible-header"><i class="material-icons">drag_handle</i>@title</div>
@ -216,7 +263,7 @@
</div> </div>
</li> </li>
<!-- Modal Structure --> <!-- Modal Chanels -->
<div id="modalChanels" class="modal"> <div id="modalChanels" class="modal">
<div class="modal-content" style="padding-bottom: 0px"> <div class="modal-content" style="padding-bottom: 0px">
<div class="row" style="margin-bottom: 0px"> <div class="row" style="margin-bottom: 0px">
@ -235,6 +282,8 @@
</div> </div>
<!--Loading Modal-->
<div id="modal_loading" class="modal valign-wrapper"> <div id="modal_loading" class="modal valign-wrapper">
<div class="modal-content" > <div class="modal-content" >
<div class="row center"> <div class="row center">