diff --git a/client/footer.html b/client/footer.html new file mode 100644 index 0000000..15552a8 --- /dev/null +++ b/client/footer.html @@ -0,0 +1,36 @@ + diff --git a/client/footer.js b/client/footer.js new file mode 100644 index 0000000..8737988 --- /dev/null +++ b/client/footer.js @@ -0,0 +1,54 @@ +Template.footer.helpers({ + 'hidePlayer': function(){ + return Session.get('hidePlayer'); + }, + 'music_isPlaying': function(){ + return Session.get('isPlaying'); + }, + 'music_title': function(){ + return Session.get('playerTitle'); + }, + 'music_thumbnail': function(){ + return Session.get('playerThumbnail'); + }, + 'music_url': function(){ + return Session.get('musicUrl'); + } +}); + +Template.footer.events({ + 'click .applink-playMusic': function(){ + Session.set('isPlaying', true); + var player = document.getElementsByTagName("audio")[0]; + player.play(); + }, + 'click .applink-pauseMusic': function(){ + + Session.set('isPlaying', false); + var player = document.getElementsByTagName("audio")[0]; + player.pause(); + + }, + 'click .applink-stopMusic': function(){ + + Session.set('isPlaying', false); + Session.set('musicUrl', ''); + Session.set('playerThumbnail', null); + Session.set('playerTitle', ''); + var player = document.getElementsByTagName("audio")[0]; + player.removeAttribute("src"); + player.load(); + Sessio.set('hidePlayer', true); + + }, + 'click .applink-skipMusic': function(){ + + Session.set('isPlaying', true); + + } +}); + +Template.footer.rendered = function () { + +}; + diff --git a/client/globalhelpers.js b/client/globalhelpers.js new file mode 100644 index 0000000..5b66fb5 --- /dev/null +++ b/client/globalhelpers.js @@ -0,0 +1,3 @@ +Template.registerHelper('getBaseUrl', function(){ + return Meteor.absoluteUrl(''); +}); \ No newline at end of file diff --git a/client/loading.html b/client/loading.html new file mode 100644 index 0000000..8beda7d --- /dev/null +++ b/client/loading.html @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/client/main.html b/client/main.html new file mode 100644 index 0000000..1019ac6 --- /dev/null +++ b/client/main.html @@ -0,0 +1,11 @@ + + + + y2bt + + + + + + + diff --git a/client/main.js b/client/main.js new file mode 100644 index 0000000..3c2d8af --- /dev/null +++ b/client/main.js @@ -0,0 +1,2 @@ +Session.set('isPlaying', false); +Session.set('hidePlayer', true); \ No newline at end of file diff --git a/client/master_layout.html b/client/master_layout.html new file mode 100644 index 0000000..47a74fe --- /dev/null +++ b/client/master_layout.html @@ -0,0 +1,7 @@ + diff --git a/client/nav.html b/client/nav.html new file mode 100644 index 0000000..d4c2aaf --- /dev/null +++ b/client/nav.html @@ -0,0 +1,18 @@ + diff --git a/client/nav.js b/client/nav.js new file mode 100644 index 0000000..9de0b4a --- /dev/null +++ b/client/nav.js @@ -0,0 +1,3 @@ +Template.nav.rendered = function () { + $(".button-collapse").sideNav(); +}; diff --git a/client/page_not_found.html b/client/page_not_found.html new file mode 100644 index 0000000..a12eae5 --- /dev/null +++ b/client/page_not_found.html @@ -0,0 +1,10 @@ + diff --git a/client/stylesheets/style.css b/client/stylesheets/style.css new file mode 100644 index 0000000..93f37de --- /dev/null +++ b/client/stylesheets/style.css @@ -0,0 +1,102 @@ +html { + position: relative; + min-height: 100%; +} + +body { + font-family: "Open Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif /*rtl:prepend:"Droid Arabic Kufi","Droid Sans", */; + background: #fcfcfc url(/imgs/bg.jpg) repeat repeat; + margin: 0px; + /* Margin bottom by footer height */ + margin-bottom: 70px; + padding: 0px; + color: #555555; + min-width: 320px; +} + +@media only screen and (min-width: 993px) { + #content { + margin-left: 240px; + } +} + +footer { + position: absolute; + bottom: 0; + width: 100%; + height: 70px; +} + +footer > .content { + padding-right: 15px; + padding-left: 15px; +} + +header, +main, +footer { + padding-left: 240px; +} + +@media only screen and (max-width: 992px) { + header, + main, + footer { + padding-left: 0; + } +} + +.container { + padding: 0 1.5rem; + margin: 0 auto; + max-width: 1280px; + width: 100%; +} + +@media only screen and (min-width: 601px) { + .container { + width: 99%; + } +} + +@media only screen and (min-width: 993px) { + .container { + width: 98%; + } +} + +nav { + background-color: #31354e; +} + +footer.page-footer { + position: fixed; + bottom: 0; + width: 100%; + left: 0; + height: 55px; + background-color: #31354e; + z-index: 1; +} + +table { + margin-left:10px; + margin-right:10px; +} + +#at-nav-button { + color: white; + background-color: #31354e; + margin-top: 10px; +} + +.promo-caption { + font-size: 1.7rem; + font-weight: 500; + margin-top: 5px; + margin-bottom: 0; +} + +.cursor-pointer{ + cursor: pointer; +} diff --git a/client/views/add.html b/client/views/add.html new file mode 100644 index 0000000..329a107 --- /dev/null +++ b/client/views/add.html @@ -0,0 +1,63 @@ + \ No newline at end of file diff --git a/client/views/add.js b/client/views/add.js new file mode 100644 index 0000000..332704b --- /dev/null +++ b/client/views/add.js @@ -0,0 +1,145 @@ +Template.add.helpers({ + 'musicTitle': function(){ + return Session.get('musicTitle_tmp'); + }, + 'loadingMusic': function(){ + return Session.get('loadingMusic'); + }, + 'addingMusic': function(){ + return Session.get('addingMusic'); + } +}); + +Template.add.events({ + 'click .applink-getMusic': function(){ + + Session.set('loadingMusic', true); + Session.set('addingMusic', true); + + var videoUrl = $('#youtubeurl').val(); + + Meteor.call('getVideoInfo', videoUrl, function(err, result) { + + var videoFileName = "/home/bitnami/htdocs/video/".concat(result.video_id).concat(".mp4"); + var musicFileName = "/home/bitnami/htdocs/music/".concat(result.video_id).concat(".mp3"); + + Session.set('musicTitle_tmp', result.title); + Session.set('musicUrl_tmp', "http://bitnami-meanstack-2dab.cloudapp.net".concat("/music/".concat(result.video_id).concat(".mp3"))); + Session.set('musicLocation', musicFileName); + Session.set('videoLocation', videoFileName); + Session.set('musicThumbnail_tmp', result.thumbnail_url); + Session.set('videoObject_tmp', result); + + console.log(result); + console.log(err); + + //console.log (result.thumbnail_url); + Session.set('loadingMusic', false); + + }); + + }, + 'click .applink-addMusic': function(){ + + Session.set('loadingMusic', true); + + var videoFileName = Session.get('videoLocation'); + var musicFileName = Session.get('musicLocation'); + + Meteor.call('convertVideo', videoFileName, musicFileName, function(err, result){ + + Session.set('musicUrl', Session.get('musicUrl_tmp')); + Session.set('musicTitle', Session.get('musicTitle_tmp')); + Session.set('playerTitle', Session.get('musicTitle_tmp')); + Session.set('musicThumbnail', Session.get('musicThumbnail_tmp')); + Session.set('playerThumbnail', Session.get('musicThumbnail_tmp')); + Session.set('addingMusic', false); + Session.set('loadingMusic', false); + + console.log("Video Converted and saved."); + + Session.set('isPlaying', true); + Session.set('hidePlayer', false); + + var player = document.getElementsByTagName("audio")[0]; + + var video_object = Session.get('videoObject_tmp'); + var title = ""; + var artist = ""; + var artistFilled = false; + + var title_split = video_object.title.split('-'); + console.log(title_split); + + var index, len; + for (index = 0, len = title_split.length; index < len; ++index) { + + //console.log(title_split[index]); + element = title_split[index]; + element = element.trim(); + console.log(element); + + if(!artistFilled){ + + if(isNaN(element)) { + + artist = element; + artistFilled = true; + + } + } + else{ + title += " ".concat(element); + console.log(title); + } + } + + var music_info = { + "userId": Meteor.userId(), + "createdAt": new Date(), + "plays": 0, + "videoId": video_object.video_id, + "thumbail": video_object.thumbnail_url, + "avg_rating": video_object.avg_rating, + "title": title, + "artist": artist, + "length": video_object.length_seconds, + "location": Session.get('musicUrl_tmp') + }; + + //console.log(music_info); + + Meteor.call('insertMusic', music_info); + //Session.set('musicUrl', musicFileName); + + var audioWrapper = document.getElementById("musicPlayerWrapper"); + audioWrapper.innerHTML = ""; + + audioWrapper.innerHTML = ''; + + audio = document.getElementsByTagName("audio"); + + /****************/ + audio[0].load();//suspends and restores all audio element + + //audio[0].play(); changed based on Sprachprofi's comment below + audio.oncanplaythrough = audio[0].play(); + /****************/ + + }); + + }, + 'click .applink-cancelAdd': function(){ + + Session.set('loadingMusic', false); + Session.set('addingMusic', false); + + } +}); + +Template.add.rendered = function () { + Session.set('musicTitle', null); + Session.set('loadingMusic', false); + Session.set('addingMusic', false); +}; + diff --git a/client/views/home.html b/client/views/home.html new file mode 100644 index 0000000..b11ad1f --- /dev/null +++ b/client/views/home.html @@ -0,0 +1,13 @@ + diff --git a/client/views/private.html b/client/views/private.html new file mode 100644 index 0000000..03d11d5 --- /dev/null +++ b/client/views/private.html @@ -0,0 +1,35 @@ + \ No newline at end of file diff --git a/client/views/private.js b/client/views/private.js new file mode 100644 index 0000000..76fbe26 --- /dev/null +++ b/client/views/private.js @@ -0,0 +1,82 @@ +Template.private.helpers({ + 'hasMusic': function(){ + if(Meteor.music.find().count() > 0){ + return true; + } + else return false; + }, + 'musicCount': function(){ + return Meteor.music.find().count(); + }, + 'musicList': function(){ + return Meteor.music.find().fetch(); + }, + 'readableTime': function(seconds){ + var date = new Date(null); + date.setSeconds(seconds); + + var minute_left0 = ""; + var second_left0 = ""; + + if(date.getUTCMinutes() < 10){ + minute_left0 = "0"; + } + + if(date.getUTCSeconds() < 10){ + second_left0 = "0"; + } + + var time = minute_left0 + date.getUTCMinutes() + ":" + second_left0 + date.getUTCSeconds(); + return time; + }, + 'isPlaying': function(location){ + if(location && Session.get('isPlaying')){ + if(Session.get('musicUrl') == location) return true; + else return false; + } else { + if(Session.get('isPlaying')) return true; + } + + return false; + } +}); + +Template.private.events({ + 'click .applink-playMusic': function(){ + + Session.set('musicUrl', this.location); + Session.set('musicTitle', this.title); + Session.set('playerTitle', this.artist + " - " + this.title); + Session.set('playerThumbnail', this.thumbnail); + Session.set('isPlaying', true); + Session.set('hidePlayer', false); + + var audioWrapper = document.getElementById("musicPlayerWrapper"); + audioWrapper.innerHTML = ""; + + audioWrapper.innerHTML = ''; + + audio = document.getElementsByTagName("audio"); + + /****************/ + audio[0].load();//suspends and restores all audio element + + //audio[0].play(); changed based on Sprachprofi's comment below + audio.oncanplaythrough = audio[0].play(); + /****************/ + + Session.set('hidePlayer', false); + Session.set('isPlaying', true); + + }, + 'click .applink-pauseMusic': function(){ + Session.set('isPlaying', false); + //Session.set('hidePlayer', false); + var player = document.getElementsByTagName("audio")[0]; + player.pause(); + } +}); + +Template.private.rendered = function () { + +}; diff --git a/client/wait.html b/client/wait.html new file mode 100644 index 0000000..36d81c5 --- /dev/null +++ b/client/wait.html @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/lib/config/accounts_t9n.js b/lib/config/accounts_t9n.js new file mode 100644 index 0000000..509b3e2 --- /dev/null +++ b/lib/config/accounts_t9n.js @@ -0,0 +1 @@ +T9n.setLanguage('en'); \ No newline at end of file diff --git a/lib/config/at_config.js b/lib/config/at_config.js new file mode 100644 index 0000000..bd0b723 --- /dev/null +++ b/lib/config/at_config.js @@ -0,0 +1,27 @@ +// Options +AccountsTemplates.configure({ + // defaultLayout: 'emptyLayout', + showForgotPasswordLink: true, + overrideLoginErrors: true, + enablePasswordChange: true, + + // sendVerificationEmail: true, + // enforceEmailVerification: true, + //confirmPassword: true, + //continuousValidation: false, + //displayFormLabels: true, + //forbidClientAccountCreation: true, + //formValidationFeedback: true, + //homeRoutePath: '/', + //showAddRemoveServices: false, + //showPlaceholders: true, + + negativeValidation: true, + positiveValidation: true, + negativeFeedback: false, + positiveFeedback: true, + + // Privacy Policy and Terms of Use + //privacyUrl: 'privacy', + //termsUrl: 'terms-of-use', +}); diff --git a/lib/router/routes.js b/lib/router/routes.js new file mode 100644 index 0000000..c79a310 --- /dev/null +++ b/lib/router/routes.js @@ -0,0 +1,32 @@ +Router.configure({ + layoutTemplate: 'masterLayout', + loadingTemplate: 'loading', + notFoundTemplate: 'pageNotFound', + yieldTemplates: { + nav: {to: 'nav'}, + footer: {to: 'footer'}, + } +}); + +Router.map(function() { + this.route('home', { + path: '/', + }); + + this.route('private'); + this.route('add'); + +}); + +Router.plugin('ensureSignedIn', { + only: ['private', 'add'] +}); + +//Routes +AccountsTemplates.configureRoute('changePwd'); +AccountsTemplates.configureRoute('enrollAccount'); +AccountsTemplates.configureRoute('forgotPwd'); +AccountsTemplates.configureRoute('resetPwd'); +AccountsTemplates.configureRoute('signIn'); +AccountsTemplates.configureRoute('signUp'); +AccountsTemplates.configureRoute('verifyEmail'); diff --git a/lib/y2bt.js b/lib/y2bt.js new file mode 100644 index 0000000..2fd8bff --- /dev/null +++ b/lib/y2bt.js @@ -0,0 +1,13 @@ +Meteor.music = new Mongo.Collection("music"); + +if (Meteor.isServer) { + Meteor.publish("music", function(){ + return Meteor.music.find({}); + }); + console.log("Published music collection to clients"); +} + +if(Meteor.isClient){ + Meteor.subscribe("music"); + console.log("Subscribed to music collection!"); +} \ No newline at end of file diff --git a/packages.json b/packages.json new file mode 100644 index 0000000..a9a2706 --- /dev/null +++ b/packages.json @@ -0,0 +1,3 @@ +{ + "ytdl-core":"0.7.9" +} \ No newline at end of file diff --git a/packages/npm-container/.npm/package-new-am4q7i/.gitignore b/packages/npm-container/.npm/package-new-am4q7i/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/packages/npm-container/.npm/package-new-am4q7i/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/packages/npm-container/index.js b/packages/npm-container/index.js new file mode 100644 index 0000000..c3fc862 --- /dev/null +++ b/packages/npm-container/index.js @@ -0,0 +1,9 @@ +Meteor.npmRequire = function(moduleName) { + var module = Npm.require(moduleName); + return module; +}; + +Meteor.require = function(moduleName) { + console.warn('Meteor.require is deprecated. Please use Meteor.npmRequire instead!'); + return Meteor.npmRequire(moduleName); +}; \ No newline at end of file diff --git a/packages/npm-container/package.js b/packages/npm-container/package.js new file mode 100644 index 0000000..9fab3ce --- /dev/null +++ b/packages/npm-container/package.js @@ -0,0 +1,30 @@ +var path = Npm.require('path'); +var fs = Npm.require('fs'); + +Package.describe({ + summary: 'Contains all your npm dependencies', + version: '1.2.0', + name: 'npm-container' +}); + +var packagesJsonFile = path.resolve('./packages.json'); +try { + var fileContent = fs.readFileSync(packagesJsonFile); + var packages = JSON.parse(fileContent.toString()); + Npm.depends(packages); +} catch (ex) { + console.error('ERROR: packages.json parsing error [ ' + ex.message + ' ]'); +} + +// Adding the app's packages.json as a used file for this package will get +// Meteor to watch it and reload this package when it changes +Package.onUse(function(api) { + api.addFiles('index.js', 'server'); + if (api.addAssets) { + api.addAssets('../../packages.json', 'server'); + } else { + api.addFiles('../../packages.json', 'server', { + isAsset: true + }); + } +}); \ No newline at end of file diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..d853173 Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/imgs/bg.jpg b/public/imgs/bg.jpg new file mode 100644 index 0000000..3132053 Binary files /dev/null and b/public/imgs/bg.jpg differ diff --git a/public/imgs/bg2.jpg b/public/imgs/bg2.jpg new file mode 100644 index 0000000..a380076 Binary files /dev/null and b/public/imgs/bg2.jpg differ diff --git a/public/imgs/ua-logo.png b/public/imgs/ua-logo.png new file mode 100644 index 0000000..97b950b Binary files /dev/null and b/public/imgs/ua-logo.png differ diff --git a/server/lib/config/accounts.js b/server/lib/config/accounts.js new file mode 100644 index 0000000..bee5315 --- /dev/null +++ b/server/lib/config/accounts.js @@ -0,0 +1,53 @@ +// Set up login services +Meteor.startup(function() { + // Add Facebook configuration entry + /* + ServiceConfiguration.configurations.update( + { service: "facebook" }, + { $set: { + appId: "XXXXXXXXXXXXXXX", + secret: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + } + }, + { upsert: true } + ); + */ + + // Add GitHub configuration entry + /* + ServiceConfiguration.configurations.update( + { service: "github" }, + { $set: { + clientId: "XXXXXXXXXXXXXXXXXXXX", + secret: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + } + }, + { upsert: true } + ); + */ + + // Add Google configuration entry + // ServiceConfiguration.configurations.update( + // { service: "google" }, + // { $set: { + // clientId: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + // client_email: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + // secret: "XXXXXXXXXXXXXXXXXXXXXXXX" + // } + // }, + // { upsert: true } + // ); + + // Add Linkedin configuration entry + /* + ServiceConfiguration.configurations.update( + { service: "linkedin" }, + { $set: { + clientId: "XXXXXXXXXXXXXX", + secret: "XXXXXXXXXXXXXXXX" + } + }, + { upsert: true } + ); + */ +}); diff --git a/server/lib/config/email.js b/server/lib/config/email.js new file mode 100644 index 0000000..88e4002 --- /dev/null +++ b/server/lib/config/email.js @@ -0,0 +1,24 @@ +/* +Accounts.emailTemplates.siteName = "MySite"; + +Accounts.emailTemplates.from = "MySite "; + +Accounts.emailTemplates.resetPassword.subject = function (user) { + return "Message for " + user.profile.displayName; +}; + +Accounts.emailTemplates.resetPassword.text = function (user, url) { + var signature = "MySite Bot"; + //var president = President.findOne(); + //if (president) + // president = Meteor.users.findOne(president.presidentId); + // signature = president.profile.displayName + ", the MySite President."; + + return "Dear " + user.profile.displayName + ",\n\n" + + "Click the following link to set your new password:\n" + + url + "\n\n" + + "Please never forget it again!!!\n\n\n" + + "Cheers,\n" + + signature; +}; +*/ diff --git a/server/server.js b/server/server.js new file mode 100644 index 0000000..18b2f56 --- /dev/null +++ b/server/server.js @@ -0,0 +1,64 @@ +// load future from fibers +var Future = Meteor.npmRequire("fibers/future"); + +// load ytdl-core +var ytdl = Meteor.npmRequire('ytdl-core'); + +// load fluent-ffmpeg to convert video to audio +var ffmpeg = Meteor.npmRequire('fluent-ffmpeg'); + +// load Node.js filesystem module +var fs = Meteor.npmRequire('fs'); + +Meteor.methods({ + // Get info from Youtube video + 'getVideoInfo':function(videoUrl) { + this.unblock(); + var future = new Future(); + + ytdl.getInfo(videoUrl, function(err, result) { + + var videoFileName = "/home/bitnami/htdocs/video/".concat(result.video_id.concat('.mp4')); + console.log(videoFileName); + + var stream = fs.createWriteStream(videoFileName); + + ytdl.downloadFromInfo(result, { filter: function(format) { return format.container === 'mp4'; } }).pipe(stream); + + future.return(result) + }); + + return future.wait(); + }, + 'convertVideo':function(videoFileName, musicFileName) { + + this.unblock(); + var future = new Future(); + + var stream = fs.createWriteStream(musicFileName); + + converter = new ffmpeg({source:videoFileName}); + converter.setFfmpegPath('/usr/bin/ffmpeg'); + converter.format('mp3'); + converter.withAudioCodec('libmp3lame').toFormat('mp3'); + converter.on('error', function(err) { + console.log('An error occurred: ' + err.message); + }); + converter.on('end', function() { + console.log('Processing finished !'); + future.return(true); + }) + + converter.writeToStream(stream, { end: true }); + + return future.wait(); + + }, + 'insertMusic':function(music_details){ + + Meteor.music.insert(music_details); + console.log(music_details); + return true; + + } +}); \ No newline at end of file