Merge branch 'devel'

This commit is contained in:
Sebastien 2018-11-22 01:03:30 +02:00
commit a650662cf1
11 changed files with 566 additions and 110 deletions

View File

@ -0,0 +1,68 @@
package net.Broken.Commands;
import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import net.Broken.Commande;
import net.dv8tion.jda.core.EmbedBuilder;
import net.dv8tion.jda.core.events.message.MessageReceivedEvent;
import java.awt.*;
public class Code implements Commande {
@Override
public void action(String[] args, MessageReceivedEvent event) {
StringBuilder stringBuilder = new StringBuilder();
for(String arg : args){
stringBuilder.append(arg);
stringBuilder.append(" ");
}
Binding binding = new Binding();
binding.setVariable("event", event);
GroovyShell shell = new GroovyShell(binding);
EmbedBuilder builder;
try{
Object value = shell.evaluate(stringBuilder.toString());
StringBuilder stringResult = new StringBuilder();
if(value.getClass().isArray()){
Object[] array = (Object[]) value;
for(Object obj : array){
if(stringResult.length() < 1800){
stringResult.append(obj.toString()).append("\n\n");
}
else{
stringResult.append("\n...");
break;
}
}
}else{
stringResult.append(value.toString());
}
builder = new EmbedBuilder().setColor(Color.orange).setTitle(":hammer_pick: Compilation Successful :hammer_pick:").setDescription("```java\n" + stringResult.toString() + "```");
}catch (Exception ex){
builder = new EmbedBuilder().setColor(Color.red).setTitle(":x: Compilation Failed :x:").setDescription("```java\n" + ex.toString() + "```");
}
event.getChannel().sendMessage(builder.build()).queue();
}
@Override
public boolean isPrivateUsable() {
return true;
}
@Override
public boolean isAdminCmd() {
return true;
}
@Override
public boolean isNSFW() {
return false;
}
}

View File

@ -0,0 +1,65 @@
package net.Broken.Commands;
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
import net.Broken.Commande;
import net.Broken.MainBot;
import net.Broken.Tools.EmbedMessageUtils;
import net.Broken.Tools.MessageTimeOut;
import net.Broken.audio.Youtube.SearchResult;
import net.Broken.audio.Youtube.YoutubeTools;
import net.dv8tion.jda.core.EmbedBuilder;
import net.dv8tion.jda.core.entities.Message;
import net.dv8tion.jda.core.entities.MessageEmbed;
import net.dv8tion.jda.core.events.message.MessageReceivedEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.util.ArrayList;
public class YtSearch implements Commande {
private Logger logger = LogManager.getLogger();
@Override
public void action(String[] args, MessageReceivedEvent event) {
YoutubeTools youtubeT = YoutubeTools.getInstance();
if(args.length < 1){
logger.info("YtSearch: Missing args, user: " + event.getAuthor().getName());
Message message = event.getChannel().sendMessage(EmbedMessageUtils.buildStandar(EmbedMessageUtils.getError("Missing search query!"))).complete();
new MessageTimeOut(MainBot.messageTimeOut, message, event.getMessage()).start();
}else {
try {
ArrayList<SearchResult> result = youtubeT.search(args[0], 5);
for(SearchResult item : result){
event.getChannel().sendMessage(EmbedMessageUtils.searchResult(item)).queue();
}
} catch (GoogleJsonResponseException e) {
logger.error("There was a service error: " + e.getDetails().getCode() + " : " + e.getDetails().getMessage());
event.getChannel().sendMessage(EmbedMessageUtils.getInternalError()).queue();
} catch (IOException t) {
logger.catching(t);
event.getChannel().sendMessage(EmbedMessageUtils.getInternalError()).queue();
}
}
}
@Override
public boolean isPrivateUsable() {
return false;
}
@Override
public boolean isAdminCmd() {
return false;
}
@Override
public boolean isNSFW() {
return false;
}
}

View File

@ -1,20 +1,15 @@
package net.Broken;
import net.Broken.RestApi.ApiCommandLoader;
import net.Broken.Tools.Command.CommandParser;
import net.Broken.Tools.EmbedMessageUtils;
import net.Broken.Tools.MessageTimeOut;
import net.Broken.Tools.PrivateMessage;
import net.Broken.Tools.UserSpamUtils;
import net.Broken.audio.Youtube.YoutubeTools;
import net.dv8tion.jda.core.AccountType;
import net.dv8tion.jda.core.JDA;
import net.dv8tion.jda.core.JDABuilder;
import net.dv8tion.jda.core.Permission;
import net.dv8tion.jda.core.entities.ChannelType;
import net.dv8tion.jda.core.entities.Member;
import net.dv8tion.jda.core.entities.Message;
import net.dv8tion.jda.core.entities.User;
import net.dv8tion.jda.core.events.message.MessageReceivedEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -24,7 +19,6 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Controller;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;

View File

@ -1,5 +1,6 @@
package net.Broken.RestApi;
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
import net.Broken.Commands.Music;
@ -7,10 +8,13 @@ import net.Broken.DB.Entity.UserEntity;
import net.Broken.DB.Repository.UserRepository;
import net.Broken.MainBot;
import net.Broken.RestApi.Data.*;
import net.Broken.Tools.EmbedMessageUtils;
import net.Broken.Tools.UserManager.Exceptions.UnknownTokenException;
import net.Broken.Tools.UserManager.UserUtils;
import net.Broken.audio.AudioM;
import net.Broken.audio.FindGeneral;
import net.Broken.audio.Youtube.SearchResult;
import net.Broken.audio.Youtube.YoutubeTools;
import net.dv8tion.jda.core.entities.Guild;
import net.dv8tion.jda.core.entities.VoiceChannel;
import org.apache.logging.log4j.LogManager;
@ -21,6 +25,7 @@ import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@ -44,7 +49,7 @@ public class MusicWebAPIController {
@RequestMapping("/currentMusicInfo")
public ResponseEntity<CurrentMusicData> getCurrentM(@RequestParam(value = "guild") String guildId){
public ResponseEntity<CurrentMusicData> getCurrentM(@RequestParam(value = "guild") String guildId){ //TODO security issue ???!!!
Guild guild = MainBot.jda.getGuildById(guildId);
if(guild == null ){
logger.warn("Request whit no guild!");
@ -72,7 +77,7 @@ public class MusicWebAPIController {
}
@RequestMapping("/getPlaylist")
public ResponseEntity<PlaylistData> getPlaylist(@RequestParam(value = "guild") String guildId){
public ResponseEntity<PlaylistData> getPlaylist(@RequestParam(value = "guild") String guildId){ //TODO security issue ???!!!
Guild guild = MainBot.jda.getGuildById(guildId);
if(guild == null ){
logger.warn("Request whit no guild!");
@ -127,7 +132,7 @@ public class MusicWebAPIController {
}
@RequestMapping(value = "/getChanel", method = RequestMethod.GET)
public ResponseEntity<List<ChanelData>> getChanel(@RequestParam(value = "guild") String guildId){
public ResponseEntity<List<ChanelData>> getChanel(@RequestParam(value = "guild") String guildId){ //TODO security issue ???!!!
Guild guild = MainBot.jda.getGuildById(guildId);
if(guild == null ){
logger.warn("Request whit no guild!");
@ -143,6 +148,33 @@ public class MusicWebAPIController {
return new ResponseEntity<>(temp, HttpStatus.OK);
}
@RequestMapping(value = "/search", method = RequestMethod.GET)
public ResponseEntity<List<SearchResult>> search(@CookieValue("token") String token, @RequestParam(value = "query") String query ){
if(token != null) {
try {
UserEntity user = userUtils.getUserWithApiToken(userRepository, token);
YoutubeTools youtubeTools = YoutubeTools.getInstance();
ArrayList<SearchResult> result = youtubeTools.search(query, 25);
return new ResponseEntity<>(result, HttpStatus.OK);
}catch (UnknownTokenException e){
logger.warn("Search without token!");
return new ResponseEntity<>( HttpStatus.UNAUTHORIZED);
} catch (GoogleJsonResponseException e) {
logger.error("There was a service error: " + e.getDetails().getCode() + " : " + e.getDetails().getMessage());
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
} catch (IOException e) {
logger.catching(e);
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}else{
logger.warn("Search without token!");
return new ResponseEntity<>( HttpStatus.UNAUTHORIZED);
}
}
}

View File

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

View File

@ -13,6 +13,7 @@ import net.dv8tion.jda.core.entities.Guild;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingDeque;
@ -190,7 +191,7 @@ public class TrackScheduler extends AudioEventAdapter {
} catch (GoogleJsonResponseException e) {
logger.error("There was a service error: " + e.getDetails().getCode() + " : " + e.getDetails().getMessage());
} catch (Throwable t) {
} catch (IOException t) {
logger.catching(t);
}

View File

@ -0,0 +1,23 @@
package net.Broken.audio.Youtube;
public class SearchResult {
public String id;
public String title;
public String description;
public String publishedAt;
public String channelId;
public String channelTittle;
public String imageUrl;
public String duration;
public SearchResult(com.google.api.services.youtube.model.SearchResult result, String duration){
id = result.getId().getVideoId();
title = result.getSnippet().getTitle();
description = result.getSnippet().getDescription();
publishedAt = result.getSnippet().getPublishedAt().toString();
channelId = result.getSnippet().getChannelId();
channelTittle = result.getSnippet().getChannelTitle();
imageUrl = result.getSnippet().getThumbnails().getDefault().getUrl();
this.duration = duration;
}
}

View File

@ -1,14 +1,12 @@
package net.Broken.audio.Youtube;
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.youtube.YouTube;
import com.google.api.services.youtube.model.SearchListResponse;
import com.google.api.services.youtube.model.SearchResult;
import net.dv8tion.jda.core.entities.Guild;
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.Logger;
@ -16,34 +14,40 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import static org.hibernate.engine.jdbc.Size.LobMultiplier.M;
public class YoutubeTools {
private Logger logger = LogManager.getLogger();
private String apiKey = System.getenv("GOOGLE_API_KEY");
private static YoutubeTools INSTANCE;
private static YoutubeTools INSTANCE ;
private YoutubeTools(){
private YoutubeTools() {
}
public static YoutubeTools getInstance(){
if(INSTANCE == null)
public static YoutubeTools getInstance() {
if (INSTANCE == null)
INSTANCE = new YoutubeTools();
return INSTANCE;
}
public String getRelatedVideo(String videoId, ArrayList<String> history) throws IOException, GoogleJsonResponseException, Throwable {
private YouTube getYoutubeService() {
// YouTube youtube = getYouTubeService();
YouTube.Builder builder = new YouTube.Builder(new NetHttpTransport(), new JacksonFactory(), new HttpRequestInitializer() {
public void initialize(HttpRequest request) throws IOException {
}
YouTube.Builder builder = new YouTube.Builder(new NetHttpTransport(), new JacksonFactory(), request -> {
});
builder.setApplicationName("youtube-cmdline-search-sample");
YouTube youtube = builder.build();
builder.setApplicationName("BotDiscord");
return builder.build();
}
public String getRelatedVideo(String videoId, ArrayList<String> history) throws IOException {
YouTube youtube = getYoutubeService();
HashMap<String, String> parameters = new HashMap<>();
@ -60,15 +64,14 @@ public class YoutubeTools {
searchListRelatedVideosRequest.setType(parameters.get("type"));
}
searchListRelatedVideosRequest.setKey(System.getenv("GOOGLE_API_KEY"));
searchListRelatedVideosRequest.setKey(apiKey);
SearchListResponse response = searchListRelatedVideosRequest.execute();
for(SearchResult item : response.getItems()){
if(!history.contains(item.getId().getVideoId())){
for (SearchResult item : response.getItems()) {
if (!history.contains(item.getId().getVideoId())) {
return item.getId().getVideoId();
}
else
} else
logger.debug("ID already on history");
}
@ -76,4 +79,93 @@ public class YoutubeTools {
return response.getItems().get(0).getId().getVideoId();
}
public ArrayList<net.Broken.audio.Youtube.SearchResult> search(String query, long max) throws IOException {
YouTube youTube = getYoutubeService();
YouTube.Search.List searchList = youTube.search().list("snippet");
searchList.setType("video");
searchList.setSafeSearch("none");
searchList.setMaxResults(max);
searchList.setQ(query);
searchList.setKey(apiKey);
searchList.setOrder("relevance");
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<>();
for(SearchResult item : response.getItems()){
logger.debug(item.getSnippet().getTitle());
finalResult.add(new net.Broken.audio.Youtube.SearchResult(item, videoHashMap.get(item.getId().getVideoId()).getContentDetails().getDuration()));
}
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

@ -7,4 +7,5 @@
.collapsible-body{
padding: 0px;
}
}

View File

@ -15,7 +15,7 @@ var loadingFlag = false;
var guild;
$(document).ready(function () {
if (Cookies.get('guild') != undefined) {
if (Cookies.get('guild') !== undefined) {
guild = Cookies.get('guild');
btn_play = $('#btn_play');
@ -28,7 +28,8 @@ $(document).ready(function () {
switchAutoFlow = $("#autoflow");
setInterval("getCurentMusic()", 1000);
$('#modalAdd').modal();
M.Modal.init($('#modalAdd').get(0));
$('#modal_current_info').modal();
@ -75,7 +76,7 @@ function getCurentMusic() {
$('#btn_info').addClass("determinate").removeClass("indeterminate");
}
$('#music_progress').width("0%");
if (Cookies.get('token') != undefined) {
if (Cookies.get('token') !== undefined) {
disableBtn(btn_stop);
disableBtn(btn_info);
enableBtn(btn_add);
@ -298,7 +299,7 @@ function updateControl(data) {
}
$('#music_progress').width(percent + "%");
if (Cookies.get('token') != undefined) {
if (Cookies.get('token') !== undefined) {
enableBtn(btn_play);
enableBtn(btn_stop);
enableBtn(btn_info);
@ -327,7 +328,7 @@ function updateControl(data) {
function sendCommand(command) {
modal_loading.modal('open');
console.log(command);
// console.log(command);
$.ajax({
type: "POST",
dataType: 'json',
@ -343,13 +344,19 @@ function sendCommand(command) {
}).fail(function (data) {
console.log(data);
alert(data.responseJSON.Message);
modal_loading.modal('close');
if (data.responseJSON.error === "token") {
Cookies.remove('token');
Cookies.remove('name');
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;
}
if (list1.length != list2.length) {
if (list1.length !== list2.length) {
return false;
}
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 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) {
var milliseconds = parseInt((duration % 1000) / 100)
, seconds = parseInt((duration / 1000) % 60)
@ -403,6 +508,8 @@ function listeners() {
});
$('#btn_search').click(search);
$('#btn_next').click(function () {
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 () {
if ($('#btn_ok_channel').hasClass("disabled")) {
$('#btn_ok_channel').removeClass("disabled");
@ -432,18 +559,6 @@ function listeners() {
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 () {
var command = {
@ -458,7 +573,7 @@ function listeners() {
});
switchAutoFlow.click(function () {
console.log(switchAutoFlow.is(':checked'))
// console.log(switchAutoFlow.is(':checked'));
if (switchAutoFlow.is(':checked')) {
sendCommand({command: 'AUTOFLOWON'})
}

View File

@ -10,15 +10,50 @@
<!-- CSS -->
<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/style.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 rel="manifest" href="/manifest.json"/>
<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>
<body class="blue-grey lighten-5" >
<!--/*@thymesVar id="guild_name" type="java.lang.String"*/-->
<!--/*@thymesVar id="redirect_url" type="java.lang.String"*/-->
<!--/*@thymesVar id="isAdmin" type="java.lang.Boolean"*/-->
<div th:replace="header :: header ('music',${guild_name},${redirect_url}, ${isAdmin})">...</div>
<div class="section no-pad-bot main" id="index-banner">
<div class="row">
@ -86,60 +121,7 @@
<!-- 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>
<!-- 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 class="col l3 m2 s2 center " style="padding-left: 0px">
<div class="row switch blue-grey-text text-darken-3" style="margin-bottom: 0px">
@ -195,6 +177,74 @@
</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-->
<li id="playlist_template" style="visibility: hidden">
<div class="collapsible-header"><i class="material-icons">drag_handle</i>@title</div>
@ -213,7 +263,7 @@
</div>
</li>
<!-- Modal Structure -->
<!-- Modal Chanels -->
<div id="modalChanels" class="modal">
<div class="modal-content" style="padding-bottom: 0px">
<div class="row" style="margin-bottom: 0px">
@ -232,6 +282,8 @@
</div>
<!--Loading Modal-->
<div id="modal_loading" class="modal valign-wrapper">
<div class="modal-content" >
<div class="row center">