diff --git a/server/handlers/list.js b/server/handlers/list.js index 447a46dd..b9cfcc77 100644 --- a/server/handlers/list.js +++ b/server/handlers/list.js @@ -436,6 +436,8 @@ function send_play(coll, socket) if(conf[0].adminpass !== "") conf[0].adminpass = true; if(conf[0].hasOwnProperty("userpass") && conf[0].userpass != "") conf[0].userpass = true; else conf[0].userpass = false; + if(!np.hasOwnProperty("start")) np.start = 0; + if(!np.hasOwnProperty("end")) np.end = np.duration; toSend = {np: np, conf: conf, time: Functions.get_time()}; if(socket === undefined) { io.to(coll).emit("np", toSend); diff --git a/server/handlers/list_change.js b/server/handlers/list_change.js index 52e2a947..cec7a0df 100644 --- a/server/handlers/list_change.js +++ b/server/handlers/list_change.js @@ -3,11 +3,14 @@ function add_function(arr, coll, guid, offline, socket) { if(typeof(arr) === 'object' && arr !== undefined && arr !== null && arr !== "" && !isNaN(parseInt(arr.duration))) { - if(coll == "" || coll == undefined || coll == null) { + if(coll == "" || coll == undefined || coll == null || !arr.hasOwnProperty("start") || !arr.hasOwnProperty("end")) { socket.emit("update_required"); return; } + var start = arr.start; + var end = arr.end; + db.collection(coll).find({views:{$exists:true}}, function(err, docs){ if(docs.length > 0 && (docs[0].userpass == undefined || docs[0].userpass == "" || (arr.hasOwnProperty('pass') && docs[0].userpass == Functions.decrypt_string(socketid, arr.pass)))) { @@ -78,7 +81,7 @@ function add_function(arr, coll, guid, offline, socket) { } else { np = false; } - db.collection(coll).update({id: id}, {"added": added,"guids":guids,"id":id,"now_playing":np,"title":title,"votes":votes, "duration":duration}, {upsert: true}, function(err, docs){ + db.collection(coll).update({id: id}, {"added": added,"guids":guids,"id":id,"now_playing":np,"title":title,"votes":votes, "duration":duration, "start": start, "end": end}, {upsert: true}, function(err, docs){ if(np) { List.send_list(coll, undefined, false, true, false); @@ -117,6 +120,8 @@ function add_function(arr, coll, guid, offline, socket) { "title":title, "votes":1, "duration":duration, + "start": start, + "end": end, "type":"suggested"} }, {upsert:true}, function(err, docs){ diff --git a/server/public/assets/css/style.css b/server/public/assets/css/style.css index 7db7c7b7..3b509acc 100755 --- a/server/public/assets/css/style.css +++ b/server/public/assets/css/style.css @@ -1272,6 +1272,19 @@ hide mdi-action-visibility mdi-action-visibility-off display:none; } +.result-start-end-container { + display: inline-flex; + align-items: center; +} + +.result-start-end-container input.result-start, .result-start-end-container input.result-end { + width: 50px; + margin: 0px 10px 0px 10px; + text-align: center; + border: 1px solid #d3d3d342; + height: 24px; +} + #inner-results { height: calc(100vh - 64px - 76px); overflow-y: scroll; @@ -1720,13 +1733,40 @@ nav ul li:hover, nav ul li.active { border-radius: 3px; margin: 15px 20px; } + +.result-info-title-length { + display: flex; + flex-direction: column; + justify-content: center; +} + .result{ height:100px; - margin-left: 40px; - margin-right: 40px; + /*margin-left: 40px; + margin-right: 40px;*/ + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; } + +.result-info-buttons { + width: 165px; +} + +.result-info-no-buttons { + display: flex; + width: calc(100% - 165px); + align-items: center; +} + +.thumb-and-info { + display: flex; + flex-direction: row; +} + #add-many{ - float:right; + float:none; color:white; } #add-many:hover{ @@ -1735,7 +1775,7 @@ nav ul li:hover, nav ul li.active { #add-many i{ line-height: 36px !important;} .open-externally { - float:right; + float:none; color:white; } @@ -1767,6 +1807,9 @@ nav ul li:hover, nav ul li.active { .search-title{ height: 40px; + /*padding-top: 33px; + margin-bottom: -16px; + line-height: initial;*/ } .list-remove{ @@ -1829,7 +1872,17 @@ nav ul li:hover, nav ul li.active { /*width:93%;*/ } .result_info{ - opacity:0.8; + opacity: 0.8; + margin-left: -144.44px; + margin-top: 64px; + margin-right: 90px; + background: black; + height: 21px; + padding: 0px 7px; + line-height: initial; + border-top-right-radius: 3px; + display: flex; + align-items: center; } #suggestions { @@ -2756,6 +2809,27 @@ nav ul li:hover, nav ul li.active { #inner-results { height: calc(100vh - 54px - 64px - 76px); overflow-y: scroll; + overflow-x: hidden; + } + + .thumb-and-info { + flex-direction: column; + } + + .result_info { + opacity: 0.8; + margin-top: 0px; + height: 21px; + margin-right: 0px; + padding: 0px; + line-height: initial; + border-top-right-radius: 3px; + display: flex; + align-items: center; + justify-content: center; + width: 55px; + margin-left: 10px; + margin-top: -16px; } #results{ @@ -2766,11 +2840,24 @@ nav ul li:hover, nav ul li.active { margin: 0; width: 99%; } + + .result-start-end-container { + visibility: hidden; + pointer-events: none; + } + + .result-info-buttons { + margin-top: 20px; + } + .result .search-title{ white-space: nowrap; + width: calc(100vw - 123px); + margin-top: -5px; + z-index: 9999; } .result img { - margin: 25px 10px; + margin: -3px 10px; height: 50px; width: 88.88px; } diff --git a/server/public/assets/js/list.js b/server/public/assets/js/list.js index de75fa71..07c73520 100755 --- a/server/public/assets/js/list.js +++ b/server/public/assets/js/list.js @@ -220,9 +220,10 @@ var List = { Helper.log("---------FULL PLAYLIST-----"); Helper.log(full_playlist); Helper.log("---------------------------"); - if(full_playlist.length > 1){ $.each(full_playlist, function(j, _current_song){ + if(!_current_song.hasOwnProperty("start")) full_playlist[j].start = 0; + if(!_current_song.hasOwnProperty("end")) full_playlist[j].end = full_playlist[j].duration; if(!_current_song.now_playing){ //check that the song isnt playing var generated = List.generateSong(_current_song, false, lazy_load, true, false, "", true) $("#wrapper").append(generated); @@ -478,7 +479,6 @@ var List = { Player.sendNext({title: full_playlist[0].title, videoId: full_playlist[0].id}); } } - if(full_playlist.length <= 2){ List.empty = true; $("#wrapper").html("The playlist is empty."); @@ -920,7 +920,9 @@ var List = { var video_thumb = "background-image:url('//img.youtube.com/vi/"+video_id+"/mqdefault.jpg');"; var song = $("
"+list_html+"
"); var image_attr = "style"; - + if(_song_info.hasOwnProperty("start") && _song_info.hasOwnProperty("end")) { + _song_info.duration = _song_info.end - _song_info.start; + } var attr; var del_attr; //song.find(".list-song"); diff --git a/server/public/assets/js/listeners.js b/server/public/assets/js/listeners.js index 5fd982c5..5df75f4f 100755 --- a/server/public/assets/js/listeners.js +++ b/server/public/assets/js/listeners.js @@ -1700,11 +1700,27 @@ $(document).on( "click", ".result-object", function(e){ var $html = $(e.target); var substr = $html.prop('outerHTML').substring(0,4); - if(substr != " original_length) { + end = original_length; + } + if(start > end) { + Materialize.toast("Start can't be before the end..", 3000, "red lighten"); + } else if(start < 0) { + Materialize.toast("Start can't be less than 0..", 3000, "red lighten"); + } else { + try { + var length = parseInt(end) - parseInt(start); + Search.submitAndClose(id, title, length, start, end); + } catch(e) { + Materialize.toast("Only numbers are accepted as song start and end parameters..", 3000, "red lighten"); + } + } } }); @@ -1725,9 +1741,28 @@ $(document).on('submit', '#contact-form', function(e){ $(document).on( "click", "#add-many", function(e){ var id = $(this).attr("data-video-id"); var title = $(this).attr("data-video-title"); - var length = $(this).attr("data-video-length"); - $(this).parent().parent().remove(); - Search.submit(id, title, length); + var original_length = $(this).attr("data-video-length"); + var parent = $(this).parent().parent(); + + var start = parseInt($(parent).find(".result-start").val()); + var end = parseInt($(parent).find(".result-end").val()); + if(end > original_length) { + end = original_length; + } + if(start > end) { + Materialize.toast("Start can't be before the end..", 3000, "red lighten"); + } else if(start < 0) { + Materialize.toast("Start can't be less than 0..", 3000, "red lighten"); + } else { + try { + var length = parseInt(end) - parseInt(start); + $(this).parent().parent().remove(); + Search.submit(id, title, length, false, 0, 1, start, end); + } catch(e) { + Materialize.toast("Only numbers are accepted as song start and end parameters..", 3000, "red lighten"); + } + } + }); $(document).on( "click", ".vote-container", function(e){ @@ -1747,7 +1782,7 @@ $(document).on( "click", ".add-suggested", function(e){ var title = $(this).attr("data-video-title"); var length = $(this).attr("data-video-length"); var added_by = $(this).attr("data-added-by"); - Search.submit(id, title, length); + Search.submit(id, title, length, false, 0, 1, 0, length); if(added_by == "user") { number_suggested = number_suggested - 1; if(number_suggested < 0) number_suggested = 0; diff --git a/server/public/assets/js/player.js b/server/public/assets/js/player.js index 3d8635f0..a9a732a5 100755 --- a/server/public/assets/js/player.js +++ b/server/public/assets/js/player.js @@ -6,6 +6,7 @@ var Player = { player: "", stopInterval: false, fireplace: "", + np: {}, youtube_listener: function(obj) { var state; @@ -68,9 +69,15 @@ var Player = { Player.stopVideo(); } video_id = obj.np[0].id; + Player.np = { + id: video_id, + start: obj.np[0].start, + end: obj.np[0].end, + duration: obj.np[0].duration, + }; conf = obj.conf[0]; time = obj.time; - seekTo = time - conf.startTime; + seekTo = (time - conf.startTime) + Player.np.start; song_title = obj.np[0].title; duration = obj.np[0].duration; Player.setBGimage(video_id); @@ -83,14 +90,20 @@ var Player = { } video_id = obj.np[0].id; + Player.np = { + id: video_id, + start: obj.np[0].start, + end: obj.np[0].end, + duration: obj.np[0].duration, + }; conf = obj.conf[0]; time = obj.time; - seekTo = time - conf.startTime; + seekTo = (time - conf.startTime) + Player.np.start; song_title = obj.np[0].title; duration = obj.np[0].duration; if(mobile_beginning && Helper.mobilecheck() && seekTo === 0 && !chromecastAvailable) { - seekTo = 1; + seekTo = 1 + Player.np.start; } try{ @@ -273,17 +286,23 @@ var Player = { } else if(!offline){ Player.player.seekTo(_seekTo); } else { - Player.player.seekTo(0); + Player.player.seekTo(0 + Player.np.start); } }, - loadVideoById: function(id, this_duration){ + loadVideoById: function(id, this_duration, start, end){ if(chromecastAvailable){ castSession.sendMessage("urn:x-cast:zoff.me", {type: "loadVideo", videoId: id, channel: chan.toLowerCase()}); chrome.cast.media.GenericMediaMetadata({metadataType: "GENERIC", title:song_title, image: 'https://img.youtube.com/vi/'+id+'/mqdefault.jpg'}); chrome.cast.Image('https://img.youtube.com/vi/'+id+'/mqdefault.jpg'); } else { - Player.player.loadVideoById({'videoId': id, 'startSeconds': 0, 'endSeconds': this_duration}); + var s; + var e; + if(start) s = start; + else s = Player.np.start; + if(end) e = end; + else e = Player.np.end; + Player.player.loadVideoById({'videoId': id, 'startSeconds': s, 'endSeconds': e}); } }, @@ -311,14 +330,20 @@ var Player = { time = (new Date()).getTime(); song_title = next_song.title; duration = next_song.duration; + var start; + var end; + if(next_song.hasOwnProperty("start")) start = next_song.start; + else start = 0; + if(next_song.hasOwnProperty("end")) end = next_song.end; + else end = duration; Player.getTitle(song_title, viewers); Player.setBGimage(video_id); if(chromecastAvailable){ - castSession.sendMessage("urn:x-cast:zoff.me", {type: "loadVideo", videoId: video_id, channel: chan.toLowerCase()}); + castSession.sendMessage("urn:x-cast:zoff.me", {type: "loadVideo", videoId: video_id, channel: chan.toLowerCase(), start: start, end:end}); chrome.cast.media.GenericMediaMetadata({metadataType: "GENERIC", title:song_title, image: 'https://img.youtube.com/vi/'+video_id+'/mqdefault.jpg'}); chrome.cast.Image('https://img.youtube.com/vi/'+video_id+'/mqdefault.jpg'); } else { - Player.loadVideoById(video_id, duration); + Player.loadVideoById(video_id, duration, start, end); } List.channel_function({type:"song_change", time: time}); }, @@ -333,15 +358,21 @@ var Player = { time = (new Date()).getTime(); song_title = next_song.title; duration = next_song.duration; + var start; + var end; + if(next_song.hasOwnProperty("start")) start = next_song.start; + else start = 0; + if(next_song.hasOwnProperty("end")) end = next_song.end; + else end = duration; Player.getTitle(song_title, viewers); Player.setBGimage(video_id); if(chromecastAvailable){ - castSession.sendMessage("urn:x-cast:zoff.me", {type: "loadVideo", videoId: video_id, channel: chan.toLowerCase()}); + castSession.sendMessage("urn:x-cast:zoff.me", {type: "loadVideo", videoId: video_id, channel: chan.toLowerCase(), start: start, end: end}); chrome.cast.media.GenericMediaMetadata({metadataType: "GENERIC", title:song_title, image: 'https://img.youtube.com/vi/'+video_id+'/mqdefault.jpg'}); chrome.cast.Image('https://img.youtube.com/vi/'+video_id+'/mqdefault.jpg'); } else { - Player.loadVideoById(video_id, duration); + Player.loadVideoById(video_id, duration, start, end); } List.channel_function({type:"song_change_prev", time: time}); @@ -543,9 +574,11 @@ var Player = { dMinutes = Math.floor(duration / 60); dSeconds = duration - dMinutes * 60; currDurr = Player.player.getCurrentTime() !== undefined ? Math.floor(Player.player.getCurrentTime()) : seekTo; - if(currDurr > duration) { - currDurr = duration; + if(currDurr - Player.np.start > duration) { + currDurr = duration - Player.np.start; } + currDurr = currDurr - Player.np.start; + //currDurr = currDurr - Player.np.start; minutes = Math.floor(currDurr / 60); seconds = currDurr - (minutes * 60); document.getElementById("duration").innerHTML = Helper.pad(minutes)+":"+Helper.pad(seconds)+" / "+Helper.pad(dMinutes)+":"+Helper.pad(dSeconds); @@ -558,7 +591,7 @@ var Player = { if(embed) { if(window.parentWindow && window.parentOrigin) { - window.parentWindow.postMessage({type: "duration", duration: Player.player.getCurrentTime(), full_duration: Player.player.getDuration(), percent: per}, window.parentOrigin); + window.parentWindow.postMessage({type: "duration", duration: Player.player.getCurrentTime() - Player.np.start, full_duration: Player.player.getDuration() - Player.np.end, percent: per}, window.parentOrigin); } } diff --git a/server/public/assets/js/search.js b/server/public/assets/js/search.js index cadcfd1b..a63691ea 100755 --- a/server/public/assets/js/search.js +++ b/server/public/assets/js/search.js @@ -87,6 +87,7 @@ var Search = { { var duration=song.contentDetails.duration; secs=Search.durationToSeconds(duration); + var _temp_duration = Helper.secondsToOther(secs); if(!longsongs || secs<720){ title=song.snippet.title; enc_title=title;//encodeURIComponent(title).replace(/'/g, "\\\'"); @@ -96,9 +97,8 @@ var Search = { //$("#results").append(result_html); var songs = pre_result; - songs.find(".search-title").text(title); - songs.find(".result_info").text(duration); + songs.find(".result_info").text(Helper.pad(_temp_duration[0]) + ":" + Helper.pad(_temp_duration[1])); songs.find(".thumb").attr("src", thumb); //songs.find(".add-many").attr("onclick", "submit('"+id+"','"+enc_title+"',"+secs+");"); songs.find("#add-many").attr("data-video-id", id); @@ -109,6 +109,7 @@ var Search = { songs.find("#temp-results").attr("data-video-title", enc_title); songs.find("#temp-results").attr("data-video-length", secs); songs.find(".open-externally").attr("href", "https://www.youtube.com/watch?v=" + id); + $(songs.find(".result-end")).attr("value", secs); //$($(songs).find("div")[0]).attr("id", id) //output += undefined; if(songs.html() != undefined) { @@ -276,7 +277,7 @@ var Search = { } if((Search.submitArray.length - 1) == Search.submitArrayExpected) { $.each(Search.submitArray, function(i, data){ - Search.submit(data.id, data.title, data.duration, true, i, Search.submitArray.length - 1); + Search.submit(data.id, data.title, data.duration, true, i, Search.submitArray.length - 1, 0, data.duration); }); document.getElementById("import_spotify").disabled = false; $("#import_spotify").removeClass("hide"); @@ -286,8 +287,8 @@ var Search = { } }, - submitAndClose: function(id,title,duration){ - Search.submit(id,title, duration, false, 0, 1); + submitAndClose: function(id,title,duration, start, end){ + Search.submit(id,title, duration, false, 0, 1, start, end); $("#results").html(''); Search.showSearch(); document.getElementById("search").value = ""; @@ -418,14 +419,14 @@ var Search = { } }); $.each(to_add, function(i, item){ - Search.submit(item.id, item.enc_title, item.duration, item.playlist, i, x); + Search.submit(item.id, item.enc_title, item.duration, item.playlist, i, x, 0, item.duration); }); } }); }, - submit: function(id,title,duration, playlist, num, full_num){ + submit: function(id,title,duration, playlist, num, full_num, start, end){ if(offline && document.getElementsByName("addsongs")[0].checked && document.getElementsByName("addsongs")[0].disabled){ var found_array = []; found_array = $.map(full_playlist, function(obj, index) { @@ -434,12 +435,12 @@ var Search = { } }); if(found_array.length == 0){ - List.channel_function({type: "added", value: {added: (new Date).getTime()/1000, guids: [1], id: id, title: title, duration: duration, playlist: false, now_playing: false, votes: 1}}); + List.channel_function({type: "added", start: start, end: end, value: {added: (new Date).getTime()/1000, guids: [1], id: id, title: title, duration: duration, playlist: false, now_playing: false, votes: 1}}); } else { List.vote(id, "pos"); } } else { - socket.emit("add", {id: id, title: title, adminpass: adminpass == "" ? "" : Crypt.crypt_pass(adminpass), list: chan.toLowerCase(), duration: duration, playlist: playlist, num: num, total: full_num, pass: embed ? '' : Crypt.crypt_pass(Crypt.get_userpass(chan.toLowerCase()))}); + socket.emit("add", {id: id, start: start, end: end, title: title, adminpass: adminpass == "" ? "" : Crypt.crypt_pass(adminpass), list: chan.toLowerCase(), duration: duration, playlist: playlist, num: num, total: full_num, pass: embed ? '' : Crypt.crypt_pass(Crypt.get_userpass(chan.toLowerCase()))}); }//[id, decodeURIComponent(title), adminpass, duration, playlist]); }, diff --git a/server/public/partials/channel/header.handlebars b/server/public/partials/channel/header.handlebars index 3a1531cd..67a10cac 100644 --- a/server/public/partials/channel/header.handlebars +++ b/server/public/partials/channel/header.handlebars @@ -57,16 +57,28 @@
- Thumb - -
- -
- playlist_add +
+
+ Thumb + +
+
+
+
+ + / + +
+
+
+
+ + open_in_new + +
+ playlist_add +
- - open_in_new -
diff --git a/server/routing/api.js b/server/routing/api.js index e7b20939..1374a4c7 100644 --- a/server/routing/api.js +++ b/server/routing/api.js @@ -25,7 +25,7 @@ router.route('/api/list/:channel_name').get(function(req, res) { res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); var channel_name = req.params.channel_name; - db.collection(channel_name).find({views: {$exists: false}}, {added: 1, id: 1, title: 1, votes: 1, duration: 1, type: 1, _id: 0}, function(err, docs) { + db.collection(channel_name).find({views: {$exists: false}}, {start: 1, end: 1, added: 1, id: 1, title: 1, votes: 1, duration: 1, type: 1, _id: 0}, function(err, docs) { if(docs.length > 0) { res.setHeader('Content-Type', 'application/json'); res.send(JSON.stringify(docs));