diff --git a/Gemfile b/Gemfile index edd8a46..2c27471 100644 --- a/Gemfile +++ b/Gemfile @@ -6,6 +6,9 @@ gem 'json' gem 'sass' gem 'coffee-script' +gem 'therubyracer', :require => false +gem 'barista' + gem 'awesome_print', :require => 'ap' gem 'delayed_job' gem 'lastfm', :git => 'git://github.com/magnolia-fan/ruby-lastfm.git' diff --git a/Gemfile.lock b/Gemfile.lock index 2941804..5fc6176 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -47,6 +47,8 @@ GEM activesupport (3.0.9) arel (2.0.10) awesome_print (0.4.0) + barista (1.2.1) + coffee-script (~> 2.2) builder (2.1.2) coffee-script (2.2.0) coffee-script-source @@ -66,6 +68,7 @@ GEM crack (= 0.1.8) i18n (0.5.0) json (1.5.3) + libv8 (3.3.10.2) mail (2.2.19) activesupport (>= 2.3.6) i18n (>= 0.4.0) @@ -98,6 +101,8 @@ GEM rdoc (3.6.1) sass (3.1.3) sqlite3 (1.3.3) + therubyracer (0.9.2) + libv8 (~> 3.3.10) thor (0.14.6) treetop (1.4.9) polyglot (>= 0.3.1) @@ -109,6 +114,7 @@ PLATFORMS DEPENDENCIES awesome_print + barista coffee-script delayed_job json @@ -118,3 +124,4 @@ DEPENDENCIES rails (= 3.0.9) sass sqlite3 + therubyracer diff --git a/app/coffeescripts/ajax.coffee b/app/coffeescripts/ajax.coffee new file mode 100644 index 0000000..270dded --- /dev/null +++ b/app/coffeescripts/ajax.coffee @@ -0,0 +1,70 @@ +class Ajax + + referer: false + + loadArtistData: (name) -> + search.showSpinner() + name = name.split(' ').join('+') + $.get '/artist/' +name+ '/', (data) -> + if data.status? + if data.status is 'loading' + search.showArtistPics data.pics + setTimeout () -> + this.loadArtistData name + , 3000 + else if data.status is 'corrected' + ajax.loadArtistData data.page + else if data.status is 'suggestions' + search.hideSpinner() + search.showSuggestions data.values + else if data.status == 'loading_failed' + search.hideSpinner() + search.showError() + else + this.setArchor '/artist/' +name+ '/' + pages.renderArtist data + beathaven.redrawScrollbar() + + loadSearchPage: -> + $.get '/templates/search.html', (data) -> + this.setArchor '/search/' + pages.renderSearch data + + loadSettingsPage: -> + $.get '/templates/settings.html', (data) -> + this.setArchor '/settings/' + pages.renderSettings data + + load404Page: -> + $.get '/404.html', (data) -> + $('.data-container .inner').html data + beathaven.redrawScrollbar() + + setArchor: (anchor) -> + @referer = this.getAnchor() + window.location.hash = '#' +anchor + + getAnchor: () -> + window.location.hash.substring 1; + + setTitle: (title) -> + document.title = title+ ' @ BeatHaven' + + detectPage: () -> + if m = this.getAnchor().match /\/artist\/(.+)\// + this.loadArtistData m[1] + else if this.getAnchor() == '' or Ajax.getAnchor().match /\/search\// + this.loadSearchPage(); + else if this.getAnchor().match /\/settings\// + this.loadSearchPage() + else + this.load404Page() + + +$ -> + window.ajax = new Ajax() + $('a.data.artist').live 'click', -> + ajax.loadArtistData $(this).html() + false + $(window).bind 'hashchange', -> + ajax.detectPage() diff --git a/app/coffeescripts/beathaven.coffee b/app/coffeescripts/beathaven.coffee new file mode 100644 index 0000000..a7bd775 --- /dev/null +++ b/app/coffeescripts/beathaven.coffee @@ -0,0 +1,76 @@ +$ -> + l = document.location + if l.host not in ['beathaven.org', 'localhost'] + l.href = 'http://beathaven.org/'+ l.hash + + window.beathaven = new BeatHaven() + window.vkontakte = new Vkontakte(if l.host == 'beathaven.org' then 2335068 else 2383163) + + beathaven.init() + vkontakte.init() + + $(window).resize -> + beathaven.adjustSizes() + window.setTimeout -> + beathaven.checkRedrawScrollbar() + , 500 + +class BeatHaven + + last_height: false + + init: -> + this.drawInterface() + this.adjustSizes() + ajax.detectPage() + + adjustSizes: -> + $('.data-container').height $(window).height() - $('.header-container').height() + $('.data-container').width $(window).width() - $('.player').width() + $('.player-container').height $(window).height() + $('.playlist').height $(window).height() - $('.player').height() - $('.player-container .additional-controls').height() + + $('.data-container').scrollbar() + $('.playlist').scrollbar() + + checkRedrawScrollbar: -> + focused_id = false + if document.activeElement.id? + focused_id = document.activeElement.id; + outer_height = $('.data-container > div').outerHeight() + if outer_height > 300 and outer_height != @last_height + @last_height = outer_height + this.redrawScrollbar() + if focused_id + document.getElementById(focused_id).focus() + focused_id = false + window.setTimeout -> + beathaven.checkRedrawScrollbar() + , 500 + + redrawScrollbar: -> + $('.data-container').html $('.data-container').find('.inner').first() + $('.data-container').scrollbar() + + +String::htmlsafe = -> + replaces = [ + ["\\", "\\\\"] + ["\"", """] + ["<", "<"] + [">", ">"] + ] + str = this + for item in replaces + str = str.replace item[0], item[1] + str + +String::trim = -> + str = this + while str.indexOf(' ') != -1 + str = str.replace(' ', ' ') + if str.charAt(0) == ' ' + str = str.substring 1 + if str.charAt(str.length - 1) == ' ' + str = str.substring(0, str.length - 1) + str diff --git a/app/coffeescripts/pages.coffee b/app/coffeescripts/pages.coffee new file mode 100644 index 0000000..a364b3a --- /dev/null +++ b/app/coffeescripts/pages.coffee @@ -0,0 +1,88 @@ +class Pages + + renderArtist: (data) -> + artist_info = $ ' +
+
+ ' +data.artist.name+ ' +
+

' +data.artist.name+ '

+
+ ' +data.artist.desc+ ' +
+
' + + albums_info = $ '
' + $.each data.albums, (i, album) -> + if album.year? + album_info = $ ' +
+

' +album.name+ ' (' +album.year+ ')

+
+ ' +album.name+ ' by ' +data.artist.name+ ' +
+
Add to Now Playing
+
+
+
+
+
' + + $.each album.tracks.album, (i, track) -> + track_info = $ ' +
  • +
    +
    +
    +
    + ' +(i+1)+ ' +
    ' +track.name+ '
    +
    ' +track.duration+ '
    +
    +
  • ' + + $(album_info).find('.tracklist ul').append(track_info) + + $(albums_info).append(album_info) + + $('.data-container').css backgroundImage: 'none' + $('.data-container .inner').html('').append(artist_info).append(albums_info) + + yaCounter7596904.hit ajax.getAnchor(), data.artist.name, ajax.referer + ajax.setTitle data.artist.name + + renderSearch: (data) -> + $('.data-container').css background: 'url(/images/concrete_wall_2.png) 0 -30px repeat' + $('.data-container .inner').html data + + $('.search-container') + .css('marginLeft', ($('.data-container').width() - 425) / 2 + 'px') + .css('marginTop', ($('.data-container').height() / 2 - 230)+ 'px') + .height(($('.data-container').height() - $('#search_form').height()) / 2) + + setTimeout -> + $('#search_field').bh_autocomplete + serviceUrl: '/artist/autocomplete' # Страница для обработки запросов автозаполнения + minChars: 2 # Минимальная длина запроса для срабатывания автозаполнения + delimiter: /(,|;)\s*/ # Разделитель для нескольких запросов, символ или регулярное выражение + maxHeight: 400 # Максимальная высота списка подсказок, в пикселях + width: 415 # Ширина списка + zIndex: 9999 # z-index списка + deferRequestBy: 500 # Задержка запроса (мсек) + onSelect: -> + ajax.loadArtistData() + $('#search_field').focus() + , 501 + + yaCounter7596904.hit ajax.getAnchor(), 'Artist Search', ajax.referer + ajax.setTitle 'Artist Search' + + renderSettings: (data) -> + $('.data-container').css background: 'none' + $('.data-container .inner').html data + yaCounter7596904.hit ajax.getAnchor(), 'Settings', ajax.referer + ajax.setTitle 'Settings' + $('.settings-container .tabs .tab').first().trigger 'click' + +$ -> + window.pages = new Pages() + false \ No newline at end of file diff --git a/app/coffeescripts/player.coffee b/app/coffeescripts/player.coffee new file mode 100644 index 0000000..2363970 --- /dev/null +++ b/app/coffeescripts/player.coffee @@ -0,0 +1,245 @@ +class Player + + bar_width: 330 + jp: null + scrobbled: false + + initJplayer: -> + self = this + + @jp = $("#jplayer") + @jp.jPlayer + swfPath: "/js" + supplied: "mp3" + cssSelectorAncestor: "" + cssSelector: + play: "#player .play" + pause: "#player .pause" + stop: "" + videoPlay: "" + seekBar: "" + playBar: "" + mute: "" + unmute: "" + volumeBar: "" + volumeBarValue: "" + currentTime: "" + duration: "" + + @jp.bind $.jPlayer.event.timeupdate, (e) -> + data = e.jPlayer.status + if not Player.scrobbled and data.currentPercentAbsolute > 50 + $obj = $('.playlist-tracks li.now') + self.scrobble $obj.attr('data-artist'), $obj.attr('data-album'), $obj.attr('data-track') + Player.scrobbled = true + $('#player .progress .loaded').width(data.seekPercent * self.bar_width / 100) + $('#player .progress .played').width(data.currentPercentAbsolute * self.bar_width / 100) + + @jp.bind $.jPlayer.event.ended, (e) -> + next = self.nextTrack() + if not next + $('#jplayer').jPlayer 'clearMedia' + $('#player .now-playing').html 'Nothing left to lose play' + $('#player .loaded, #player .played').width 0 + $('.playlist-tracks li').removeClass 'now' + else + self.setTrack next + false + + addTrack: (artist, album, track, length, autoplay) -> + if not autoplay? + autoplay = false + initial_count = $('.playlist-tracks li').length + $('.playlist-tracks').append ' +
  • +
    +
    + ' +artist+ ' &mdash ' +track+ ' + ' +length+ ' +
    remove
    +
    +
  • ' + + $('#playlist').html($('.playlist-tracks')).scrollbar() + $('.playlist-tracks').sortable() + + if autoplay + Player.setTrack($('.playlist-tracks li').last().attr('id').split('i')[1]) + else if initial_count == 0 and not Player.hasTrack() + Player.setTrack($('.playlist-tracks li').first().attr('id').split('i')[1]) + + setTrack: (id) -> + $obj = $('#i' +id) + query = $obj.attr('data-artist')+ ' &mdash ' +$obj.attr('data-track') + + $('#player .now-playing').html query+ '
    ' + $('.playlist-tracks li').removeClass 'now' + $obj.addClass 'now' + $('#player .loaded, #player .played').width 0 + + vkontakte.loadTracksData $obj.attr('data-artist'), $obj.attr('data-track'), $obj.attr('data-length'), -> + player.playSource() + this.updateNowListening $obj.attr('data-artist'), $obj.attr('data-album'), $obj.attr('data-track') + + hasTrack: -> + if $('#jplayer audio').length > 0 + return $('#jplayer audio').attr('src')? + else if $('#jplayer object').length > 0 + $('#jplayer').jPlayer 'play' + true + false + + playSource: (url) -> + $('#jplayer').jPlayer 'setMedia', mp3: url + $('#jplayer').jPlayer 'play' + @scrobbled = false + + nextTrack: (manual) -> + manual = manual? + cnt = $('.playlist-tracks li').length + if not this.onShuffle() # Shuffle off + if $('.playlist-tracks .now').next().length == 0 # Last track and repeat is on + if Player.onRepeat() or manual # Repeat or manual click + return $('.playlist-tracks li').first().attr('id').split('i')[1] + else + false + else + return $('.playlist-tracks .now').next().attr('id').split('i')[1] + else if cnt == 1 # Single track in the playlist + return $('.playlist-tracks li').first().attr('id').split('i')[1] + else # Shuffle on + while true + rnd = Math.floor(Math.random() * (cnt + .999)) + $li = $('.playlist-tracks li').eq rnd + if $li.length > 0 and not $li.hasClass 'now' + return $li.attr('id').split('i')[1] + false + + prevTrack: -> + cnt = $('.playlist-tracks li').length + if not Player.onShuffle() # Shuffle off + if $('.playlist-tracks .now').prev().length == 0 # First track in the playlist + return $('.playlist-tracks li').last().attr('id').split('i')[1] + else + return $('.playlist-tracks .now').prev().attr('id').split('i')[1] + else if cnt == 1 # Single track in the playlist + return $('.playlist-tracks li').first().attr('id').split('i')[1] + else # Shuffle on + while true + rnd = Math.floor(Math.random() * (cnt + .999)) + $li = $('.playlist-tracks li').eq rnd + if $li.length > 0 and not $li.hasClass 'now' + return $li.attr('id').split('i')[1] + false + + onShuffle: -> + return $('#shuffle').hasClass 'active' + + onRepeat: -> + return $('#repeat').hasClass 'active' + + updateNowListening: (artist, album, track) -> + if session.user.lastfm_username + session.query '/lastfm/listening?r=' +Math.random(), artist: artist, album: album, track: track + + scrobble: (artist, album, track) -> + if session.user.lastfm_username + session.query '/lastfm/scrobble?r=' +Math.random(), artist: artist, album: album, track: track + + +$ -> + window.player = new Player() + window.player.initJplayer() + false + + +# Player Controls + +$('#player .controls .prev').live 'click', -> + Player.setTrack Player.prevTrack() + false + +$('#player .controls .next').live 'click', -> + Player.setTrack Player.nextTrack(true) + false + +$('#player .play').live 'click', -> + if $('.playlist-tracks li').length > 0 and not Player.hasTrack() + player.setTrack $('.playlist-tracks li').first().attr('id').split('i')[1] + false + +$('#player .progress').live 'click', (e) -> + $('#jplayer').jPlayer 'playHead', Math.round((e.offsetX / Player.bar_width) * 100) + false + +# Player Additional Controls + +$('#repeat, #shuffle').live 'click', -> + $(this).toggleClass 'active' + false + +$('#empty-playlist').live 'click', -> + if confirm('Are you sure?') + $('.playlist-tracks li').remove() + $('#jplayer').jPlayer 'clearMedia' + $('#player .now-playing').text 'Add some music to playlist' + $('#player .loaded, #player .played').width 0 + false + +# Playlist Actions + +$('.playlist-tracks li .fade, .playlist-tracks li .duration, .playlist-tracks li .remove').live 'mouseover mouseout', (e) -> + if e.type == 'mouseover' + $(this).parent().find('.duration').hide() + $(this).parent().find('.remove').show() + else + $(this).parent().find('.remove').hide() + $(this).parent().find('.duration').show() + false + +$('.playlist-tracks li .remove').live 'click', -> + $li = $(this).parent().parent() + if $li.hasClass 'now' + $('#jplayer').jPlayer 'clearMedia' + $('#player .now-playing').text '...' + $('#player .loaded, #player .played').width 0 + $li.remove() + false + +$('.playlist-tracks li').live 'dblclick', -> + player.setTrack $(this).attr('id').split('i')[1] + false + +# Adding To Playlist actions + +$('.add-album').live 'click', -> + artist = $('.artist-info .name').html() + album = $(this).parent().parent().parent().find('h2.name').text().replace /\s\([\d]{4}\)$/, '' + for item in $(this).parent().parent().parent().find('.tracklist li') + track_name = $(item).find('.trackname').html() + length = $(item).find('.length').html() + Player.addTrack artist, album, track_name, length + false + +$('.add-track').live 'click', -> + artist = $('.artist-info .name').html() + album = $(this).parent().parent().parent().parent().find('h2.name').text().replace /\s\([\d]{4}\)$/, '' + track_name = $(this).parent().find('.trackname').html() + length = $(this).parent().find('.length').html() + Player.addTrack artist, album, track_name, length + false + +$('.tracklist li').live 'mouseover mouseout', (e) -> + if e.type == 'mouseover' + $(this).find('.add-track').show() + else + $(this).find('.add-track').hide() + false + +$('.tracklist li').live 'dblclick', (e) -> + artist = $('.artist-info .name').html() + album = $(this).parent().parent().parent().find('h2.name').text().replace /\s\([\d]{4}\)$/, '' + track_name = $(this).find('.trackname').html() + length = $(this).find('.length').html() + Player.addTrack artist, album, track_name, length, true + false diff --git a/app/coffeescripts/search.coffee b/app/coffeescripts/search.coffee new file mode 100644 index 0000000..d096fe4 --- /dev/null +++ b/app/coffeescripts/search.coffee @@ -0,0 +1,64 @@ +class Search + + pics: [] + + showSpinner: -> + $('.search-container input').attr(disabled: 'disabled').blur() + $('.search-container img').show() + $('.autocomplete-container').hide() + $('.artist_loading.failed').hide() + this.hideSuggestions() + false + + hideSpinner: -> + $('.search-container input').removeAttr 'disabled' + $('.search_field').focus() + $('.search-container img').hide() + false + + showSuggestions: (values) -> + for item in values + $('.suggestions ul').append ' +
  • + ' +item.name+ ' + ' +(if item.desc then '
    '+ item.desc +'' else '')+ ' +
  • ' + $('.suggestions').show() + false + + hideSuggestions: -> + $('.suggestions ul li').remove() + $('.suggestions').hide() + false + + showArtistPics: (pics) -> + $('.artist_loading.ok, .artist_pics').show() + for pic in pics + if @pics.indexOf(pic) == -1 + @pics.push(pic); + $('.artist_pics').append ' +
    + +
    ' + false + + showError: -> + $('.artist_loading.ok, .artist_pics').hide() + $('.artist_loading.failed').show() + @pics = [] + + +$ -> + window.search = new Search() + false + +$('.search').live 'click', -> + ajax.loadSearchPage() + false +$('#search_form').live 'submit', -> + $('.autocomplete-container').remove() + ajax.loadArtistData $('#search_field').val() + false +$('.suggestions a').live 'click', -> + $('#search_field').val $(this).text() + false diff --git a/app/coffeescripts/session.coffee b/app/coffeescripts/session.coffee new file mode 100644 index 0000000..0b43905 --- /dev/null +++ b/app/coffeescripts/session.coffee @@ -0,0 +1,23 @@ +class Session + + vk_params: null + user: null + + constructor: (@vk_params) -> + + query: (url, params, callback) -> + q_params = @vk_params + for attr in params + q_params[attr] = params[attr] + $.post url, q_params, callback + false + + setVkParams: (params) -> + attrs = ['expire', 'mid', 'secret', 'sid', 'sig'] + for key in attrs + @vk_params[key] = params[key] + false + +$ -> + window.session = new Session() + false \ No newline at end of file diff --git a/app/coffeescripts/settings.coffee b/app/coffeescripts/settings.coffee new file mode 100644 index 0000000..ff05e4b --- /dev/null +++ b/app/coffeescripts/settings.coffee @@ -0,0 +1,41 @@ +class Settings + + getAccountInfo: (callback) -> + session.query '/user/update/', {}, callback + + saveAccountInfo: (params, callback) -> + session.query '/user/update', params, callback + + loadFormData: (form) -> + if form == 'account' + $('.settings-container .form input[name$="username"]').val session.user.name + $('.settings-container .form input[name$="email"]').val session.email + else if form == 'lastfm' + if @user.lastfm_username + $('.form-container input[name$="username"]').first().val session.lastfm_username + +$ -> + window.settings = new Settings() + false + +$('.settings') .live 'click', -> + ajax.loadSettingsPage(); + +$('.settings-container .tabs .tab').live 'click', -> + if $(this).hasClass 'active' + $('.settings-container .tabs .tab').removeClass 'active' + $(this).addClass 'active' + $('.form-container').html $('.forms .'+ $(this).attr 'data-fieldset').html() + settings.loadFormData $(this).attr 'data-fieldset' + +$('.lastfm-connect') .live 'click', -> + window.open session.user.lastfm_login_url + +$('.settings-container .form input').live 'blur', -> + active_tab = $('.settings-container .tabs .tab.active').attr 'data-fieldset' + if active_tab == 'account' + params = + username: $('.settings-container .form input[name$="username"]').first().val() + email: $('.settings-container .form input[name$="email"]').first().val() + settings.saveAccountInfo params, -> + $('#header-container .hello .greating').text 'Hi there, ' +(if params.username.length > 0 then params.username else '%username%')+ '!' \ No newline at end of file diff --git a/app/coffeescripts/vkontakte.coffee b/app/coffeescripts/vkontakte.coffee new file mode 100644 index 0000000..ed0de1a --- /dev/null +++ b/app/coffeescripts/vkontakte.coffee @@ -0,0 +1,92 @@ +class Vkontakte + + qr: [] + + constructor: (@api_id) -> + + init: -> + VK.init + apiId: @api_id + nameTransportPath: '/xd_receiver.html' + + VK.Auth.getLoginStatus this.authInfo + + authInfo: (response) -> + if typeof response isnt 'undefined' and response.session + session.setVkParams response.session + + $('#vk_login, .auth_notice').hide() + $('#vk_logout').css display: 'block' + + $('#search_field').focus() if $('#search_field').length > 0 + + session.query '/user/auth', {}, (ar) -> + if ar.newbie + VK.Api.call 'getVariable', key: 1281, (r) -> + Session.query '/user/update', name: r.response, (ar2) -> + session.user = ar2.user + $('#header-container .hello .greating') + .text 'Hi there, ' +(if session.user.name then session.user.name else '%username%')+ '!' + else + session.user = ar.user + + $('#header-container .hello .greating') + .text 'Hi there, ' +( if session.user.name then session.user.name else '%username%')+ '!' + else + $('#vk_login, .auth_notice').css display: 'block' + $('#vk_logout').hide() + + loadTracksData: (artist, track, duration, callback) -> + track_prepared = track.replace(/\(.*\)/i, '').split('/')[0]; + query = artist +' '+ track_prepared; + if @qr[query]? + callback @qr[query] + else + VK.Api.call 'audio.search', q: query, (r) -> + url = this.matchPerfectResult r.response, artist, track, duration + @qr[query] = url; + callback url + + matchPerfectResult: (data, artist, track, duration) -> + duration = duration.split ':' + + duration = parseInt(duration[0], 10) * 60 + parseInt(duration[1], 10) + best_score = 0; + best_result = null; + for item in data + score = 0; + item.artist = item.artist.trim(); + item.title = item.title.trim(); + + if item.artist == artist + score += 10 + else if item.artist.split(artist).length is 2 + score += 5 + else if item.title.split(artist).length is 2 + score += 4 + + if item.title == track + score += 10 + else if item.title.split(track).length is 2 + score += 5 + + if parseInt(item.duration, 10) == duration + score += 15 + else + delta = Math.abs parseInt(item.duration, 10) - duration + score += (10 - delta) if delta < 10 + + if score > best_score + best_score = score + best_result = item + + if score is 35 + return best_result.url + + return best_result.url + +$ -> + $('#vk_login').click -> + VK.Auth.login vkontakte.authInfo, 8 + $('#vk_logout').click -> + VK.Auth.logout vkontakte.authInfo diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index cba5ff7..743c62c 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -23,4 +23,8 @@ class ApplicationController < ActionController::Base end end + def index + + end + end diff --git a/public/css/.gitkeep b/app/views/application/index.html.erb similarity index 100% rename from public/css/.gitkeep rename to app/views/application/index.html.erb diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 12df4b4..31c4f58 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -1,14 +1,80 @@ - - Beathaven - <%= stylesheet_link_tag :all %> - <%= javascript_include_tag :defaults %> - <%= csrf_meta_tag %> - - + + BetaHaven + + + + + <%= javascript_include_tag "jquery/jquery.min.js" %> + <%= javascript_include_tag "jquery/jquery-ui/js/jquery-ui-1.8.13.custom.min.js" %> + <%= javascript_include_tag "jquery/jquery.autocomplete.js" %> + <%= javascript_include_tag "jquery/jquery.contentchange.js" %> + <%= javascript_include_tag "jquery/jquery.jplayer.js" %> + <%= javascript_include_tag "jquery/jquery.scroll.js" %> -<%= yield %> + <%= javascript_include_tag "coffee/player.js", :type => "text/javascript", :charset => "utf-8" %> + <%= javascript_include_tag "coffee/search.js", :type => "text/javascript", :charset => "utf-8" %> + <%= javascript_include_tag "coffee/pages.js", :type => "text/javascript", :charset => "utf-8" %> + <%= javascript_include_tag "coffee/settings.js", :type => "text/javascript", :charset => "utf-8" %> + + + + <%= yield %> + +
    +
    +
    +
    Add some music to playlist
    +
    +
    +
    +
    +
    +
    + +
    +
    + +
    +
    +
    + +
    +
    +
    +
    Repeat
    +
    +
    +
    Shuffle
    +
    +
    +
    Empty Playlist
    +
    +
    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    - +
    +
    Don't forget to log in, please. It's simple.
    + + +
    + + diff --git a/config/initializers/barista_config.rb b/config/initializers/barista_config.rb new file mode 100644 index 0000000..bd5dff1 --- /dev/null +++ b/config/initializers/barista_config.rb @@ -0,0 +1,64 @@ +# Configure barista. +Barista.configure do |c| + + # Change the root to use app/scripts + c.root = Rails.root.join("app", "coffeescripts") + + # Change the output root, causing Barista to compile into public/coffeescripts + c.output_root = Rails.root.join("public", "javascripts", "coffee") + # + # Disable auto compile, use generated file directly: + # c.auto_compile = false + + # Add a new framework: + + # c.register :tests, :root => Rails.root.join('test', 'coffeescript'), :output_prefix => 'test' + + # Disable wrapping in a closure: + # c.bare = true + # ... or ... + # c.bare! + + # Change the output root for a framework: + + # c.change_output_prefix! 'framework-name', 'output-prefix' + + # or for all frameworks... + + # c.each_framework do |framework| + # c.change_output_prefix! framework, "vendor/#{framework.name}" + # end + + # or, prefix the path for the app files: + + # c.change_output_prefix! :default, 'my-app-name' + + # or, change the directory the framework goes into full stop: + + # c.change_output_prefix! :tests, Rails.root.join('spec', 'javascripts') + + # or, hook into the compilation: + + # c.before_compilation { |path| puts "Barista: Compiling #{path}" } + # c.on_compilation { |path| puts "Barista: Successfully compiled #{path}" } + # c.on_compilation_error { |path, output| puts "Barista: Compilation of #{path} failed with:\n#{output}" } + # c.on_compilation_with_warning { |path, output| puts "Barista: Compilation of #{path} had a warning:\n#{output}" } + + # Turn off preambles and exceptions on failure: + + # c.verbose = false + + # Or, make sure it is always on + # c.verbose! + + # If you want to use a custom JS file, you can as well + # e.g. vendoring CoffeeScript in your application: + # c.js_path = Rails.root.join('public', 'javascripts', 'coffee-script.js') + + # Make helpers and the HAML filter output coffee-script instead of the compiled JS. + # Used in combination with the coffeescript_interpreter_js helper in Rails. + # c.embedded_interpreter = true + + c.add_preamble = false + +end diff --git a/config/routes.rb b/config/routes.rb index 614cb29..37e66ec 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -56,6 +56,8 @@ Beathaven::Application.routes.draw do # Note: This route will make all actions in every controller accessible via GET requests. # match ':controller(/:action(/:id(.:format)))' + match '/' => 'application#index' + match 'user/auth' => 'user#auth' match 'user/update' => 'user#update' diff --git a/public/index.html b/public/index.html deleted file mode 100644 index 7f0606b..0000000 --- a/public/index.html +++ /dev/null @@ -1,81 +0,0 @@ - - - - BetaHaven - - - - - - - - - - - - - - - - - - - - - -
    -
    -
    -
    Add some music to playlist
    -
    -
    -
    -
    -
    -
    - -
    -
    - -
    -
    -
    - -
    -
    -
    -
    Repeat
    -
    -
    -
    Shuffle
    -
    -
    -
    Empty Playlist
    -
    -
    -
    -
    -
    - -
    -
    - -
    -
    -
    -
    - -
    -
    Don't forget to log in, please. It's simple.
    - - -
    - - - diff --git a/public/js/Jplayer.swf b/public/javascripts/Jplayer.swf similarity index 100% rename from public/js/Jplayer.swf rename to public/javascripts/Jplayer.swf diff --git a/public/javascripts/application.js b/public/javascripts/application.js new file mode 100644 index 0000000..e69de29 diff --git a/public/javascripts/coffee/ajax.js b/public/javascripts/coffee/ajax.js new file mode 100644 index 0000000..0a9d412 --- /dev/null +++ b/public/javascripts/coffee/ajax.js @@ -0,0 +1,87 @@ +/* DO NOT MODIFY. This file was compiled Mon, 27 Jun 2011 17:43:40 GMT from + * /Users/chez/Sites/beathaven/app/coffeescripts/ajax.coffee + */ + +(function() { + var Ajax; + Ajax = (function() { + function Ajax() {} + Ajax.prototype.referer = false; + Ajax.prototype.loadArtistData = function(name) { + search.showSpinner(); + name = name.split(' ').join('+'); + return $.get('/artist/' + name + '/', function(data) { + if (data.status != null) { + if (data.status === 'loading') { + search.showArtistPics(data.pics); + return setTimeout(function() { + return this.loadArtistData(name); + }, 3000); + } else if (data.status === 'corrected') { + return ajax.loadArtistData(data.page); + } else if (data.status === 'suggestions') { + search.hideSpinner(); + return search.showSuggestions(data.values); + } else if (data.status === 'loading_failed') { + search.hideSpinner(); + return search.showError(); + } + } else { + this.setArchor('/artist/' + name + '/'); + pages.renderArtist(data); + return beathaven.redrawScrollbar(); + } + }); + }; + Ajax.prototype.loadSearchPage = function() { + return $.get('/templates/search.html', function(data) { + this.setArchor('/search/'); + return pages.renderSearch(data); + }); + }; + Ajax.prototype.loadSettingsPage = function() { + return $.get('/templates/settings.html', function(data) { + this.setArchor('/settings/'); + return pages.renderSettings(data); + }); + }; + Ajax.prototype.load404Page = function() { + return $.get('/404.html', function(data) { + $('.data-container .inner').html(data); + return beathaven.redrawScrollbar(); + }); + }; + Ajax.prototype.setArchor = function(anchor) { + this.referer = this.getAnchor(); + return window.location.hash = '#' + anchor; + }; + Ajax.prototype.getAnchor = function() { + return window.location.hash.substring(1); + }; + Ajax.prototype.setTitle = function(title) { + return document.title = title + ' @ BeatHaven'; + }; + Ajax.prototype.detectPage = function() { + var m; + if (m = this.getAnchor().match(/\/artist\/(.+)\//)) { + return this.loadArtistData(m[1]); + } else if (this.getAnchor() === '' || Ajax.getAnchor().match(/\/search\//)) { + return this.loadSearchPage(); + } else if (this.getAnchor().match(/\/settings\//)) { + return this.loadSearchPage(); + } else { + return this.load404Page(); + } + }; + return Ajax; + })(); + $(function() { + $('a.data.artist').live('click', function() { + ajax.loadArtistData($(this).html()); + return false; + }); + return $(window).bind('hashchange', function() { + return ajax.detectPage(); + }); + }); +}).call(this); diff --git a/public/javascripts/coffee/beathaven.js b/public/javascripts/coffee/beathaven.js new file mode 100644 index 0000000..6cffaec --- /dev/null +++ b/public/javascripts/coffee/beathaven.js @@ -0,0 +1,95 @@ +/* DO NOT MODIFY. This file was compiled Mon, 27 Jun 2011 17:49:39 GMT from + * /Users/chez/Sites/beathaven/app/coffeescripts/beathaven.coffee + */ + +(function() { + var BeatHaven; + $(function() { + var ajax, beathaven, l, pages, player, search, session, settings, vkontakte, _ref; + l = document.location; + if ((_ref = l.host) !== 'beathaven.org' && _ref !== 'localhost') { + l.href = 'http://beathaven.org/' + l.hash; + } + beathaven = new BeatHaven(); + vkontakte = new Vkontakte(l.host === 'beathaven.org' ? 2335068 : 2383163); + session = new Session(); + ajax = new Ajax(); + player = new Player(); + search = new Search(); + pages = new Pages(); + settings = new Settings(); + beathaven.init(); + vkontakte.init(); + $(window).resize(function() { + return beathaven.adjustSizes(); + }); + return window.setTimeout(function() { + return beathaven.checkRedrawScrollbar(); + }, 500); + }); + BeatHaven = (function() { + function BeatHaven() {} + BeatHaven.prototype.last_height = false; + BeatHaven.prototype.init = function() { + this.drawInterface(); + this.adjustSizes(); + return ajax.detectPage(); + }; + BeatHaven.prototype.adjustSizes = function() { + $('.data-container').height($(window).height() - $('.header-container').height()); + $('.data-container').width($(window).width() - $('.player').width()); + $('.player-container').height($(window).height()); + $('.playlist').height($(window).height() - $('.player').height() - $('.player-container .additional-controls').height()); + $('.data-container').scrollbar(); + return $('.playlist').scrollbar(); + }; + BeatHaven.prototype.checkRedrawScrollbar = function() { + var focused_id, outer_height; + focused_id = false; + if (document.activeElement.id != null) { + focused_id = document.activeElement.id; + } + outer_height = $('.data-container > div').outerHeight(); + if (outer_height > 300 && outer_height !== this.last_height) { + this.last_height = outer_height; + this.redrawScrollbar(); + } + if (focused_id) { + document.getElementById(focused_id).focus(); + focused_id = false; + } + return window.setTimeout(function() { + return beathaven.checkRedrawScrollbar(); + }, 500); + }; + BeatHaven.prototype.redrawScrollbar = function() { + $('.data-container').html($('.data-container').find('.inner').first()); + return $('.data-container').scrollbar(); + }; + return BeatHaven; + })(); + String.prototype.htmlsafe = function() { + var item, replaces, str, _i, _len; + replaces = [["\\", "\\\\"], ["\"", """], ["<", "<"], [">", ">"]]; + str = this; + for (_i = 0, _len = replaces.length; _i < _len; _i++) { + item = replaces[_i]; + str = str.replace(item[0], item[1]); + } + return str; + }; + String.prototype.trim = function() { + var str; + str = this; + while (str.indexOf(' ') !== -1) { + str = str.replace(' ', ' '); + } + if (str.charAt(0) === ' ') { + str = str.substring(1); + } + if (str.charAt(str.length - 1) === ' ') { + str = str.substring(0, str.length - 1); + } + return str; + }; +}).call(this); diff --git a/public/javascripts/coffee/pages.js b/public/javascripts/coffee/pages.js new file mode 100644 index 0000000..d15f691 --- /dev/null +++ b/public/javascripts/coffee/pages.js @@ -0,0 +1,96 @@ +/* DO NOT MODIFY. This file was compiled Mon, 27 Jun 2011 17:49:39 GMT from + * /Users/chez/Sites/beathaven/app/coffeescripts/pages.coffee + */ + +(function() { + var Pages; + Pages = (function() { + function Pages() {} + Pages.prototype.renderArtist = function(data) { + var albums_info, artist_info; + artist_info = $('\ +
    \ +
    \ + ' + data.artist.name + '\ +
    \ +

    ' + data.artist.name + '

    \ +
    \ + ' + data.artist.desc + '\ +
    \ +
    '); + albums_info = $('
    '); + $.each(data.albums, function(i, album) { + var album_info; + if (album.year != null) { + album_info = $('\ +
    \ +

    ' + album.name + ' (' + album.year + ')

    \ +
    \ + ' + album.name + ' by ' + data.artist.name + '\ +
    \ +
    Add to Now Playing
    \ +
    \ +
    \ +
    \ +
    \ +
    '); + $.each(album.tracks.album, function(i, track) { + var track_info; + track_info = $('\ +
  • \ +
    +
    \ +
    \ +
    \ + ' + (i + 1) + '\ +
    ' + track.name + '
    \ +
    ' + track.duration + '
    \ +
    \ +
  • '); + return $(album_info).find('.tracklist ul').append(track_info); + }); + return $(albums_info).append(album_info); + } + }); + $('.data-container').css({ + backgroundImage: 'none' + }); + $('.data-container .inner').html('').append(artist_info).append(albums_info); + yaCounter7596904.hit(ajax.getAnchor(), data.artist.name, ajax.referer); + return ajax.setTitle(data.artist.name); + }; + Pages.prototype.renderSearch = function(data) { + $('.data-container').css({ + background: 'url(/images/concrete_wall_2.png) 0 -30px repeat' + }); + $('.data-container .inner').html(data); + $('.search-container').css('marginLeft', ($('.data-container').width() - 425) / 2 + 'px').css('marginTop', ($('.data-container').height() / 2 - 230) + 'px').height(($('.data-container').height() - $('#search_form').height()) / 2); + setTimeout(function() { + $('#search_field').bh_autocomplete({ + serviceUrl: '/artist/autocomplete', + minChars: 2, + delimiter: /(,|;)\s*/, + maxHeight: 400, + width: 415, + zIndex: 9999, + deferRequestBy: 500, + onSelect: function() { + return ajax.loadArtistData(); + } + }); + return $('#search_field').focus(); + }, 501); + yaCounter7596904.hit(ajax.getAnchor(), 'Artist Search', ajax.referer); + return ajax.setTitle('Artist Search'); + }; + Pages.prototype.renderSettings = function(data) { + $('.data-container').css({ + background: 'none' + }); + $('.data-container .inner').html(data); + yaCounter7596904.hit(ajax.getAnchor(), 'Settings', ajax.referer); + ajax.setTitle('Settings'); + return $('.settings-container .tabs .tab').first().trigger('click'); + }; + return Pages; + })(); +}).call(this); diff --git a/public/javascripts/coffee/player.js b/public/javascripts/coffee/player.js new file mode 100644 index 0000000..16893a2 --- /dev/null +++ b/public/javascripts/coffee/player.js @@ -0,0 +1,285 @@ +/* DO NOT MODIFY. This file was compiled Mon, 27 Jun 2011 17:49:39 GMT from + * /Users/chez/Sites/beathaven/app/coffeescripts/player.coffee + */ + +(function() { + var Player; + Player = (function() { + function Player() {} + Player.prototype.bar_width = 330; + Player.prototype.jp = null; + Player.prototype.scrobbled = false; + Player.prototype.initJplayer = function() { + var self; + self = this; + this.jp = $("#jplayer"); + this.jp.jPlayer({ + swfPath: "/js", + supplied: "mp3", + cssSelectorAncestor: "", + cssSelector: { + play: "#player .play", + pause: "#player .pause", + stop: "", + videoPlay: "", + seekBar: "", + playBar: "", + mute: "", + unmute: "", + volumeBar: "", + volumeBarValue: "", + currentTime: "", + duration: "" + } + }); + this.jp.bind($.jPlayer.event.timeupdate, function(e) { + var $obj, data; + data = e.jPlayer.status; + if (!Player.scrobbled && data.currentPercentAbsolute > 50) { + $obj = $('.playlist-tracks li.now'); + self.scrobble($obj.attr('data-artist'), $obj.attr('data-album'), $obj.attr('data-track')); + Player.scrobbled = true; + } + $('#player .progress .loaded').width(data.seekPercent * self.bar_width / 100); + return $('#player .progress .played').width(data.currentPercentAbsolute * self.bar_width / 100); + }); + this.jp.bind($.jPlayer.event.ended, function(e) { + var next; + next = self.nextTrack(); + if (!next) { + $('#jplayer').jPlayer('clearMedia'); + $('#player .now-playing').html('Nothing left to lose play'); + $('#player .loaded, #player .played').width(0); + return $('.playlist-tracks li').removeClass('now'); + } else { + return self.setTrack(next); + } + }); + return false; + }; + Player.prototype.addTrack = function(artist, album, track, length, autoplay) { + var initial_count; + if (!(autoplay != null)) { + autoplay = false; + } + initial_count = $('.playlist-tracks li').length; + $('.playlist-tracks').append('\ +
  • \ +
    \ +
    \ + ' + artist + ' &mdash ' + track + '\ + ' + length + '\ +
    remove
    \ +
    \ +
  • '); + $('#playlist').html($('.playlist-tracks')).scrollbar(); + $('.playlist-tracks').sortable(); + if (autoplay) { + return Player.setTrack($('.playlist-tracks li').last().attr('id').split('i')[1]); + } else if (initial_count === 0 && !Player.hasTrack()) { + return Player.setTrack($('.playlist-tracks li').first().attr('id').split('i')[1]); + } + }; + Player.prototype.setTrack = function(id) { + var $obj, query; + $obj = $('#i' + id); + query = $obj.attr('data-artist') + ' &mdash ' + $obj.attr('data-track'); + $('#player .now-playing').html(query + '
    '); + $('.playlist-tracks li').removeClass('now'); + $obj.addClass('now'); + $('#player .loaded, #player .played').width(0); + vkontakte.loadTracksData($obj.attr('data-artist'), $obj.attr('data-track'), $obj.attr('data-length'), function() { + return player.playSource(); + }); + return this.updateNowListening($obj.attr('data-artist'), $obj.attr('data-album'), $obj.attr('data-track')); + }; + Player.prototype.hasTrack = function() { + if ($('#jplayer audio').length > 0) { + return $('#jplayer audio').attr('src') != null; + } else if ($('#jplayer object').length > 0) { + $('#jplayer').jPlayer('play'); + true; + } + return false; + }; + Player.prototype.playSource = function(url) { + $('#jplayer').jPlayer('setMedia', { + mp3: url + }); + $('#jplayer').jPlayer('play'); + return this.scrobbled = false; + }; + Player.prototype.nextTrack = function(manual) { + var $li, cnt, rnd; + manual = manual != null; + cnt = $('.playlist-tracks li').length; + if (!this.onShuffle()) { + if ($('.playlist-tracks .now').next().length === 0) { + if (Player.onRepeat() || manual) { + return $('.playlist-tracks li').first().attr('id').split('i')[1]; + } else { + false; + } + } else { + return $('.playlist-tracks .now').next().attr('id').split('i')[1]; + } + } else if (cnt === 1) { + return $('.playlist-tracks li').first().attr('id').split('i')[1]; + } else { + while (true) { + rnd = Math.floor(Math.random() * (cnt + .999)); + $li = $('.playlist-tracks li').eq(rnd); + if ($li.length > 0 && !$li.hasClass('now')) { + return $li.attr('id').split('i')[1]; + } + } + } + return false; + }; + Player.prototype.prevTrack = function() { + var $li, cnt, rnd; + cnt = $('.playlist-tracks li').length; + if (!Player.onShuffle()) { + if ($('.playlist-tracks .now').prev().length === 0) { + return $('.playlist-tracks li').last().attr('id').split('i')[1]; + } else { + return $('.playlist-tracks .now').prev().attr('id').split('i')[1]; + } + } else if (cnt === 1) { + return $('.playlist-tracks li').first().attr('id').split('i')[1]; + } else { + while (true) { + rnd = Math.floor(Math.random() * (cnt + .999)); + $li = $('.playlist-tracks li').eq(rnd); + if ($li.length > 0 && !$li.hasClass('now')) { + return $li.attr('id').split('i')[1]; + } + } + } + return false; + }; + Player.prototype.onShuffle = function() { + return $('#shuffle').hasClass('active'); + }; + Player.prototype.onRepeat = function() { + return $('#repeat').hasClass('active'); + }; + Player.prototype.updateNowListening = function(artist, album, track) { + if (session.user.lastfm_username) { + return session.query('/lastfm/listening?r=' + Math.random(), { + artist: artist, + album: album, + track: track + }); + } + }; + Player.prototype.scrobble = function(artist, album, track) { + if (session.user.lastfm_username) { + return session.query('/lastfm/scrobble?r=' + Math.random(), { + artist: artist, + album: album, + track: track + }); + } + }; + return Player; + })(); + $(function() { + return player.initJplayer(); + }); + $('#player .controls .prev').live('click', function() { + Player.setTrack(Player.prevTrack()); + return false; + }); + $('#player .controls .next').live('click', function() { + Player.setTrack(Player.nextTrack(true)); + return false; + }); + $('#player .play').live('click', function() { + if ($('.playlist-tracks li').length > 0 && !Player.hasTrack()) { + player.setTrack($('.playlist-tracks li').first().attr('id').split('i')[1]); + } + return false; + }); + $('#player .progress').live('click', function(e) { + $('#jplayer').jPlayer('playHead', Math.round((e.offsetX / Player.bar_width) * 100)); + return false; + }); + $('#repeat, #shuffle').live('click', function() { + $(this).toggleClass('active'); + return false; + }); + $('#empty-playlist').live('click', function() { + if (confirm('Are you sure?')) { + $('.playlist-tracks li').remove(); + $('#jplayer').jPlayer('clearMedia'); + $('#player .now-playing').text('Add some music to playlist'); + $('#player .loaded, #player .played').width(0); + } + return false; + }); + $('.playlist-tracks li .fade, .playlist-tracks li .duration, .playlist-tracks li .remove').live('mouseover mouseout', function(e) { + if (e.type === 'mouseover') { + $(this).parent().find('.duration').hide(); + $(this).parent().find('.remove').show(); + } else { + $(this).parent().find('.remove').hide(); + $(this).parent().find('.duration').show(); + } + return false; + }); + $('.playlist-tracks li .remove').live('click', function() { + var $li; + $li = $(this).parent().parent(); + if ($li.hasClass('now')) { + $('#jplayer').jPlayer('clearMedia'); + $('#player .now-playing').text('...'); + $('#player .loaded, #player .played').width(0); + } + $li.remove(); + return false; + }); + $('.playlist-tracks li').live('dblclick', function() { + player.setTrack($(this).attr('id').split('i')[1]); + return false; + }); + $('.add-album').live('click', function() { + var album, artist, item, length, track_name, _i, _len, _ref; + artist = $('.artist-info .name').html(); + album = $(this).parent().parent().parent().find('h2.name').text().replace(/\s\([\d]{4}\)$/, ''); + _ref = $(this).parent().parent().parent().find('.tracklist li'); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + item = _ref[_i]; + track_name = $(item).find('.trackname').html(); + length = $(item).find('.length').html(); + Player.addTrack(artist, album, track_name, length); + } + return false; + }); + $('.add-track').live('click', function() { + var album, artist, length, track_name; + artist = $('.artist-info .name').html(); + album = $(this).parent().parent().parent().parent().find('h2.name').text().replace(/\s\([\d]{4}\)$/, ''); + track_name = $(this).parent().find('.trackname').html(); + length = $(this).parent().find('.length').html(); + Player.addTrack(artist, album, track_name, length); + return false; + }); + $('.tracklist li').live('mouseover mouseout', function(e) { + if (e.type === 'mouseover') { + $(this).find('.add-track').show(); + } else { + $(this).find('.add-track').hide(); + } + return false; + }); + $('.tracklist li').live('dblclick', function(e) { + var album, artist, length, track_name; + artist = $('.artist-info .name').html(); + album = $(this).parent().parent().parent().find('h2.name').text().replace(/\s\([\d]{4}\)$/, ''); + track_name = $(this).find('.trackname').html(); + length = $(this).find('.length').html(); + Player.addTrack(artist, album, track_name, length, true); + return false; + }); +}).call(this); diff --git a/public/javascripts/coffee/search.js b/public/javascripts/coffee/search.js new file mode 100644 index 0000000..d9c056e --- /dev/null +++ b/public/javascripts/coffee/search.js @@ -0,0 +1,81 @@ +/* DO NOT MODIFY. This file was compiled Mon, 27 Jun 2011 17:49:39 GMT from + * /Users/chez/Sites/beathaven/app/coffeescripts/search.coffee + */ + +(function() { + var Search; + Search = (function() { + function Search() {} + Search.prototype.pics = []; + Search.prototype.showSpinner = function() { + $('.search-container input').attr({ + disabled: 'disabled' + }).blur(); + $('.search-container img').show(); + $('.autocomplete-container').hide(); + $('.artist_loading.failed').hide(); + this.hideSuggestions(); + return false; + }; + Search.prototype.hideSpinner = function() { + $('.search-container input').removeAttr('disabled'); + $('.search_field').focus(); + $('.search-container img').hide(); + return false; + }; + Search.prototype.showSuggestions = function(values) { + var item, _i, _len; + for (_i = 0, _len = values.length; _i < _len; _i++) { + item = values[_i]; + $('.suggestions ul').append('\ +
  • \ + ' + item.name + '\ + ' + (item.desc ? '
    ' + item.desc(+'') : '') + '\ +
  • '); + } + $('.suggestions').show(); + return false; + }; + Search.prototype.hideSuggestions = function() { + $('.suggestions ul li').remove(); + $('.suggestions').hide(); + return false; + }; + Search.prototype.showArtistPics = function(pics) { + var pic, _i, _len; + $('.artist_loading.ok, .artist_pics').show(); + for (_i = 0, _len = pics.length; _i < _len; _i++) { + pic = pics[_i]; + if (this.pics.indexOf(pic) === -1) { + this.pics.push(pic); + $('.artist_pics').append('\ +
    \ + \ +
    '); + } + } + return false; + }; + Search.prototype.showError = function() { + $('.artist_loading.ok, .artist_pics').hide(); + $('.artist_loading.failed').show(); + return this.pics = []; + }; + return Search; + })(); + $(function() { + $('.search').live('click', function() { + ajax.loadSearchPage(); + return false; + }); + $('#search_form').live('submit', function() { + $('.autocomplete-container').remove(); + ajax.loadArtistData($('#search_field').val()); + return false; + }); + return $('.suggestions a').live('click', function() { + $('#search_field').val($(this).text()); + return false; + }); + }); +}).call(this); diff --git a/public/javascripts/coffee/session.js b/public/javascripts/coffee/session.js new file mode 100644 index 0000000..3ee7557 --- /dev/null +++ b/public/javascripts/coffee/session.js @@ -0,0 +1,34 @@ +/* DO NOT MODIFY. This file was compiled Mon, 27 Jun 2011 17:49:39 GMT from + * /Users/chez/Sites/beathaven/app/coffeescripts/session.coffee + */ + +(function() { + var Session; + Session = (function() { + Session.prototype.vk_params = null; + Session.prototype.user = null; + function Session(vk_params) { + this.vk_params = vk_params; + } + Session.prototype.query = function(url, params, callback) { + var attr, q_params, _i, _len; + q_params = this.vk_params; + for (_i = 0, _len = params.length; _i < _len; _i++) { + attr = params[_i]; + q_params[attr] = params[attr]; + } + $.post(url, q_params, callback); + return false; + }; + Session.prototype.setVkParams = function(params) { + var attrs, key, _i, _len; + attrs = ['expire', 'mid', 'secret', 'sid', 'sig']; + for (_i = 0, _len = attrs.length; _i < _len; _i++) { + key = attrs[_i]; + this.vk_params[key] = params[key]; + } + return false; + }; + return Session; + })(); +}).call(this); diff --git a/public/javascripts/coffee/settings.js b/public/javascripts/coffee/settings.js new file mode 100644 index 0000000..ee5e1b5 --- /dev/null +++ b/public/javascripts/coffee/settings.js @@ -0,0 +1,54 @@ +/* DO NOT MODIFY. This file was compiled Mon, 27 Jun 2011 14:00:02 GMT from + * /Users/chez/Sites/beathaven/app/coffeescripts/settings.coffee + */ + +(function() { + var Settings; + Settings = (function() { + function Settings() {} + Settings.prototype.getAccountInfo = function(callback) { + return session.query('/user/update/', {}, callback); + }; + Settings.prototype.saveAccountInfo = function(params, callback) { + return session.query('/user/update', params, callback); + }; + Settings.prototype.loadFormData = function(form) { + if (form === 'account') { + $('.settings-container .form input[name$="username"]').val(session.user.name); + return $('.settings-container .form input[name$="email"]').val(session.email); + } else if (form === 'lastfm') { + if (this.user.lastfm_username) { + return $('.form-container input[name$="username"]').first().val(session.lastfm_username); + } + } + }; + return Settings; + })(); + $('.settings').live('click', function() { + return ajax.loadSettingsPage(); + }); + $('.settings-container .tabs .tab').live('click', function() { + if ($(this).hasClass('active')) { + $('.settings-container .tabs .tab').removeClass('active'); + $(this).addClass('active'); + $('.form-container').html($('.forms .' + $(this).attr('data-fieldset')).html()); + return settings.loadFormData($(this).attr('data-fieldset')); + } + }); + $('.lastfm-connect').live('click', function() { + return window.open(session.user.lastfm_login_url); + }); + $('.settings-container .form input').live('blur', function() { + var active_tab, params; + active_tab = $('.settings-container .tabs .tab.active').attr('data-fieldset'); + if (active_tab === 'account') { + params = { + username: $('.settings-container .form input[name$="username"]').first().val(), + email: $('.settings-container .form input[name$="email"]').first().val() + }; + return settings.saveAccountInfo(params, function() { + return $('#header-container .hello .greating').text('Hi there, ' + (params.username.length > 0 ? params.username : '%username%') + '!'); + }); + } + }); +}).call(this); diff --git a/public/javascripts/coffee/vkontakte.js b/public/javascripts/coffee/vkontakte.js new file mode 100644 index 0000000..3969f00 --- /dev/null +++ b/public/javascripts/coffee/vkontakte.js @@ -0,0 +1,121 @@ +/* DO NOT MODIFY. This file was compiled Mon, 27 Jun 2011 17:49:39 GMT from + * /Users/chez/Sites/beathaven/app/coffeescripts/vkontakte.coffee + */ + +(function() { + var Vkontakte; + Vkontakte = (function() { + Vkontakte.prototype.qr = []; + function Vkontakte(api_id) { + this.api_id = api_id; + } + Vkontakte.prototype.init = function() { + VK.init({ + apiId: this.api_id, + nameTransportPath: '/xd_receiver.html' + }); + return VK.Auth.getLoginStatus(this.authInfo); + }; + Vkontakte.prototype.authInfo = function(response) { + if (typeof response !== 'undefined' && response.session) { + session.setVkParams(response.session); + $('#vk_login, .auth_notice').hide(); + $('#vk_logout').css({ + display: 'block' + }); + if ($('#search_field').length > 0) { + $('#search_field').focus(); + } + return session.query('/user/auth', {}, function(ar) { + if (ar.newbie) { + VK.Api.call('getVariable', { + key: 1281 + }, function(r) { + return Session.query('/user/update', { + name: r.response + }, function(ar2) { + session.user = ar2.user; + return $('#header-container .hello .greating').text('Hi there, ' + (session.user.name ? session.user.name : '%username%') + '!'); + }); + }); + } else { + session.user = ar.user; + } + return $('#header-container .hello .greating').text('Hi there, ' + (session.user.name ? session.user.name : '%username%') + '!'); + }); + } else { + $('#vk_login, .auth_notice').css({ + display: 'block' + }); + return $('#vk_logout').hide(); + } + }; + Vkontakte.prototype.loadTracksData = function(artist, track, duration, callback) { + var query, track_prepared; + track_prepared = track.replace(/\(.*\)/i, '').split('/')[0]; + query = artist(+' ' + track_prepared); + if (this.qr[query] != null) { + return callback(this.qr[query]); + } else { + return VK.Api.call('audio.search', { + q: query + }, function(r) { + var url; + url = this.matchPerfectResult(r.response, artist, track, duration); + this.qr[query] = url; + return callback(url); + }); + } + }; + Vkontakte.prototype.matchPerfectResult = function(data, artist, track, duration) { + var best_result, best_score, delta, item, score, _i, _len; + duration = duration.split(':'); + duration = parseInt(duration[0], 10) * 60 + parseInt(duration[1], 10); + best_score = 0; + best_result = null; + for (_i = 0, _len = data.length; _i < _len; _i++) { + item = data[_i]; + score = 0; + item.artist = item.artist.trim(); + item.title = item.title.trim(); + if (item.artist === artist) { + score += 10; + } else if (item.artist.split(artist).length === 2) { + score += 5; + } else if (item.title.split(artist).length === 2) { + score += 4; + } + if (item.title === track) { + score += 10; + } else if (item.title.split(track).length === 2) { + score += 5; + } + if (parseInt(item.duration, 10) === duration) { + score += 15; + } else { + delta = Math.abs(parseInt(item.duration, 10) - duration); + if (delta < 10) { + score += 10 - delta; + } + } + if (score > best_score) { + best_score = score; + best_result = item; + } + if (score === 35) { + return best_result.url; + } + } + return best_result.url; + }; + return Vkontakte; + })(); + $(function() { + $('#vk_login').click(function() { + return VK.Auth.login(vkontakte.authInfo, 8); + }); + return $('#vk_logout').click(function() { + return VK.Auth.logout(vkontakte.authInfo); + }); + }); +}).call(this); diff --git a/public/js/jquery/jquery-ui/js/jquery-ui-1.8.13.custom.min.js b/public/javascripts/jquery/jquery-ui/js/jquery-ui-1.8.13.custom.min.js similarity index 100% rename from public/js/jquery/jquery-ui/js/jquery-ui-1.8.13.custom.min.js rename to public/javascripts/jquery/jquery-ui/js/jquery-ui-1.8.13.custom.min.js diff --git a/public/js/jquery/jquery.autocomplete.js b/public/javascripts/jquery/jquery.autocomplete.js similarity index 100% rename from public/js/jquery/jquery.autocomplete.js rename to public/javascripts/jquery/jquery.autocomplete.js diff --git a/public/js/jquery/jquery.contentchange.js b/public/javascripts/jquery/jquery.contentchange.js similarity index 100% rename from public/js/jquery/jquery.contentchange.js rename to public/javascripts/jquery/jquery.contentchange.js diff --git a/public/js/jquery/jquery.jplayer.js b/public/javascripts/jquery/jquery.jplayer.js similarity index 100% rename from public/js/jquery/jquery.jplayer.js rename to public/javascripts/jquery/jquery.jplayer.js diff --git a/public/js/jquery/jquery.min.js b/public/javascripts/jquery/jquery.min.js similarity index 100% rename from public/js/jquery/jquery.min.js rename to public/javascripts/jquery/jquery.min.js diff --git a/public/js/jquery/jquery.scroll.js b/public/javascripts/jquery/jquery.scroll.js similarity index 100% rename from public/js/jquery/jquery.scroll.js rename to public/javascripts/jquery/jquery.scroll.js diff --git a/public/js/beathaven/ajax.js b/public/js/beathaven/ajax.js deleted file mode 100644 index 43f7267..0000000 --- a/public/js/beathaven/ajax.js +++ /dev/null @@ -1,87 +0,0 @@ -var Ajax = { - - referer: false, - - loadArtistData: function(name) { - Search.showSpinner(); - name = name.split(' ').join('+'); - $.get('/artist/'+ name +'/', function(data){ - if (typeof data.status != 'undefined') { - if (data.status == 'loading') { - Search.showArtistPics(data.pics); - setTimeout(function() { - Ajax.loadArtistData(name); - }, 3000); - } else if (data.status == 'corrected') { - Ajax.loadArtistData(data.page); - } else if (data.status == 'suggestions') { - Search.hideSpinner(); - Search.showSuggestions(data.values); - } else if (data.status == 'loading_failed') { - Search.hideSpinner(); - Search.showError(); - } - return false; - } else { - Ajax.setArchor('/artist/'+ name +'/'); - Pages.renderArtist(data); - beathaven.redrawScrollbar(); - } - }) - }, - - loadSearchPage: function() { - $.get('/templates/search.html', function(data){ - Ajax.setArchor('/search/'); - Pages.renderSearch(data); - }) - }, - - loadSettingsPage: function() { - $.get('/templates/settings.html', function(data){ - Ajax.setArchor('/settings/'); - Pages.renderSettings(data); - }) - }, - - load404Page: function() { - $.get('/404.html', function(data){ - $('.data-container .inner').html(data); - beathaven.redrawScrollbar(); - }) - }, - - setArchor: function(anchor) { - Ajax.referer = Ajax.getAnchor(); - window.location.hash = '#'+ anchor; - }, - - getAnchor: function() { - return window.location.hash.substring(1); - }, - - setTitle: function(title) { - document.title = title +' @ BeatHaven'; - }, - - detectPage: function() { - if (m = Ajax.getAnchor().match(/\/artist\/(.+)\//)) { - Ajax.loadArtistData(m[1]); - } else if (Ajax.getAnchor() === '' || Ajax.getAnchor().match(/\/search\//)) { - Ajax.loadSearchPage(); - } else if (Ajax.getAnchor().match(/\/settings\//)) { - Ajax.loadSearchPage(); - } else { - Ajax.load404Page(); - } - } -} - - -$(function(){ - $('a.data.artist').live('click', function(){ - Ajax.loadArtistData($(this).html()); - return false; - }); - //$(window).bind('hashchange', Ajax.detectPage); -}) \ No newline at end of file diff --git a/public/js/beathaven/layout.js b/public/js/beathaven/layout.js deleted file mode 100644 index f9ee42c..0000000 --- a/public/js/beathaven/layout.js +++ /dev/null @@ -1,80 +0,0 @@ -$(function(){ - if (document.location.host != 'beathaven.org' && document.location.host != 'localhost') { - document.location.href = 'http://beathaven.org/'+ document.location.hash; - } - beathaven.init(); - $(window).resize(beathaven.adjustSizes) - window.setTimeout(beathaven.checkRedrawScrollbar, 500); -}) -var beathaven = { - - last_height: false, - - init: function () { - this.drawInterface(); - this.adjustSizes(); - Ajax.detectPage(); - }, - - drawInterface: function() { - }, - - adjustSizes: function() { - $('.data-container').height($(window).height() - $('.header-container').height()); - $('.data-container').width($(window).width() - $('.player').width()).scrollbar(); - $('.player-container').height($(window).height()); - $('.playlist').height($(window).height() - $('.player').height() - $('.player-container .additional-controls').height()); - - $('.playlist').scrollbar(); - }, - - checkRedrawScrollbar: function() { - var focused_id = false; - if (typeof document.activeElement.id !== 'undefined') { - focused_id = document.activeElement.id; - } - var outer_height = $('.data-container > div').outerHeight(); - if (outer_height > 300 && outer_height != beathaven.last_height) { - beathaven.last_height = outer_height; - beathaven.redrawScrollbar(); - } - if (focused_id) { - document.getElementById(focused_id).focus(); - focused_id = false; - } - window.setTimeout(beathaven.checkRedrawScrollbar, 500); - }, - - redrawScrollbar: function() { - $('.data-container').html($('.data-container').find('.inner').first()); - $('.data-container').scrollbar(); - } -} - -String.prototype.htmlsafe = function() { - var replaces = [ - ["\\", "\\\\"], - ["\"", """], - ["<", "<"], - [">", ">"] - ]; - var str = this; - for (var i = 0; i < replaces.length; i++) { - str = str.replace(replaces[i][0], replaces[i][1]); - } - return str; -} - -String.prototype.trim = function() { - var str = this; - while (str.indexOf(' ') !== -1) { - str = str.replace(' ', ' '); - } - if (str.charAt(0) == ' ') { - str = str.substring(1); - } - if (str.charAt(str.length - 1) == ' ') { - str = str.substring(0, str.length - 1); - } - return str; -} \ No newline at end of file diff --git a/public/js/beathaven/pages.js b/public/js/beathaven/pages.js deleted file mode 100644 index b6fdd5e..0000000 --- a/public/js/beathaven/pages.js +++ /dev/null @@ -1,97 +0,0 @@ -var Pages = { - - renderArtist: function(data){ - var artist_info = $('\ -
    \ -
    \ - '+ data.artist.name +'\ -
    \ -

    '+ data.artist.name +'

    \ -
    \ - '+ data.artist.desc +'\ -
    \ -
    \ - '); - - var albums_info = $('
    '); - $.each(data.albums, function(i, album){ - if (album.year != null) { - var album_info = $('\ -
    \ -

    '+ album.name +' ('+ album.year +')

    \ -
    \ - '+ album.name +' by '+ data.artist.name +'\ -
    \ -
    Add to Now Playing
    \ -
    \ -
    \ -
    \ - \ -
    \ -
    \ -
    \ - '); - - $.each(album.tracks.album, function(i, track){ - var track_info = $('\ -
  • \ -
    +
    \ -
    \ -
    \ - '+ (i+1) +'\ -
    '+ track.name +'
    \ -
    '+ track.duration +'
    \ -
    \ -
  • \ - '); - - $(album_info).find('.tracklist ul').append(track_info); - }); - - $(albums_info).append(album_info); - } - }) - - $('.data-container').css('backgroundImage', 'none'); - $('.data-container .inner').html('').append(artist_info).append(albums_info); - - yaCounter7596904.hit(Ajax.getAnchor(), data.artist.name, Ajax.referer); - Ajax.setTitle(data.artist.name); - }, - - renderSearch: function(data) { - $('.data-container').css('background', 'url(/images/concrete_wall_2.png) 0 -30px repeat'); - $('.data-container .inner').html(data); - - $('.search-container') - .css('marginLeft', ($('.data-container').width() - 425) / 2 + 'px') - .css('marginTop', ($('.data-container').height() / 2 - 230) +'px') - .height(($('.data-container').height() - $('#search_form').height()) / 2); - - setTimeout(function(){ - $('#search_field').bh_autocomplete({ - serviceUrl: '/artist/autocomplete', // Страница для обработки запросов автозаполнения - minChars: 2, // Минимальная длина запроса для срабатывания автозаполнения - delimiter: /(,|;)\s*/, // Разделитель для нескольких запросов, символ или регулярное выражение - maxHeight: 400, // Максимальная высота списка подсказок, в пикселях - width: 415, // Ширина списка - zIndex: 9999, // z-index списка - deferRequestBy: 500, // Задержка запроса (мсек) - onSelect: Ajax.loadArtistData - }); - $('#search_field').focus(); - }, 501) - - yaCounter7596904.hit(Ajax.getAnchor(), 'Artist Search', Ajax.referer); - Ajax.setTitle('Artist Search'); - }, - - renderSettings: function(data) { - $('.data-container').css('background', 'none'); - $('.data-container .inner').html(data); - yaCounter7596904.hit(Ajax.getAnchor(), 'Settings', Ajax.referer); - Ajax.setTitle('Settings'); - $('.settings-container .tabs .tab').first().trigger('click'); - } -} \ No newline at end of file diff --git a/public/js/beathaven/player.js b/public/js/beathaven/player.js deleted file mode 100644 index 076926d..0000000 --- a/public/js/beathaven/player.js +++ /dev/null @@ -1,261 +0,0 @@ -var Player = { - - bar_width: 330, - jp: null, - scrobbled: false, - - initJplayer: function() { - this.jp = $("#jplayer"); - this.jp.jPlayer({ - swfPath: "/js", - supplied: "mp3", - cssSelectorAncestor: "", - cssSelector: { - play: "#player .play", - pause: "#player .pause", - stop: "", - videoPlay: "", - seekBar: "", - playBar: "", - mute: "", - unmute: "", - volumeBar: "", - volumeBarValue: "", - currentTime: "", - duration: "" - } - }); - this.jp.bind($.jPlayer.event.timeupdate, function(e){ - data = e.jPlayer.status; - if (!Player.scrobbled && data.currentPercentAbsolute > 50) { - var $obj = $('.playlist-tracks li.now'); - Player.scrobble($obj.attr('data-artist'), $obj.attr('data-album'), $obj.attr('data-track')); - Player.scrobbled = true; - } - $('#player .progress .loaded').width(data.seekPercent * Player.bar_width / 100); - $('#player .progress .played').width(data.currentPercentAbsolute * Player.bar_width / 100); - }); - this.jp.bind($.jPlayer.event.ended, function(e){ - var next = Player.nextTrack(); - if (next === false) { - $('#jplayer').jPlayer('clearMedia'); - $('#player .now-playing').html('Nothing left to lose play'); - $('#player .loaded, #player .played').width(0); - $('.playlist-tracks li').removeClass('now'); - } else { - Player.setTrack(next); - } - }); - }, - - addTrack: function(artist, album, track, length, autoplay) { - if (typeof autoplay === 'undefined') { - autoplay = false; - } - var initial_count = $('.playlist-tracks li').length; - $('.playlist-tracks').append('\ -
  • \ -
    \ -
    \ - '+ artist +' — '+ track +'\ - '+ length +'\ -
    remove
    \ -
    \ -
  • \ - '); - - $('#playlist').html($('.playlist-tracks')).scrollbar(); - $('.playlist-tracks').sortable(); - - if (autoplay) { - Player.setTrack($('.playlist-tracks li').last().attr('id').split('i')[1]); - } else if (initial_count === 0 && !Player.hasTrack()) { - Player.setTrack($('.playlist-tracks li').first().attr('id').split('i')[1]); - } - }, - - setTrack: function(id) { - var $obj = $('#i'+ id); - var query = $obj.attr('data-artist') +' — '+ $obj.attr('data-track'); - - $('#player .now-playing').html(query +'
    '); - $('.playlist-tracks li').removeClass('now'); - $obj.addClass('now'); - $('#player .loaded, #player .played').width(0); - - Vkontakte.loadTracksData($obj.attr('data-artist'), $obj.attr('data-track'), $obj.attr('data-length'), Player.playSource); - Player.updateNowListening($obj.attr('data-artist'), $obj.attr('data-album'), $obj.attr('data-track')); - }, - - hasTrack: function() { - if ($('#jplayer audio').length > 0) { - return typeof $('#jplayer audio').attr('src') !== 'undefined'; - } else if ($('#jplayer audio').length > 0) { - $('#jplayer').jPlayer('play'); - return true; - } - return false; - }, - - playSource: function(url) { - $('#jplayer').jPlayer('setMedia', {mp3: url}).jPlayer('play'); - Player.scrobbled = false; - }, - - nextTrack: function(manual) { - var manual = typeof manual !== 'undefined' - var cnt = $('.playlist-tracks li').length; - if (!Player.onShuffle()) { // Shuffle off - if ($('.playlist-tracks .now').next().length == 0 && true) { - if (Player.onRepeat() || manual) { // Last track and repeat is on - return $('.playlist-tracks li').first().attr('id').split('i')[1]; - } else { - return false; - } - } else { - return $('.playlist-tracks .now').next().attr('id').split('i')[1]; - } - } else if (cnt === 1) { // Single track in the playlist - return $('.playlist-tracks li').first().attr('id').split('i')[1]; - } else { // Shuffle on - while (1) { - var rnd = Math.floor(Math.random() * (cnt + .999)); - var $li = $('.playlist-tracks li').eq(rnd); - if ($li.length > 0 && !$li.hasClass('now')) { - return $li.attr('id').split('i')[1]; - } - } - } - }, - - prevTrack: function() { - var cnt = $('.playlist-tracks li').length; - if (!Player.onShuffle()) { // Shuffle off - if ($('.playlist-tracks .now').prev().length == 0 && true) { // First track in the playlist - return $('.playlist-tracks li').last().attr('id').split('i')[1]; - } else { - return $('.playlist-tracks .now').prev().attr('id').split('i')[1]; - } - } else if (cnt === 1) { // Single track in the playlist - return $('.playlist-tracks li').first().attr('id').split('i')[1]; - } else { // Shuffle on - while (1) { - var rnd = Math.floor(Math.random() * (cnt + .999)); - var $li = $('.playlist-tracks li').eq(rnd); - if ($li.length > 0 && !$li.hasClass('now')) { - return $li.attr('id').split('i')[1]; - } - } - } - }, - - onShuffle: function() { - return $('#shuffle').hasClass('active'); - }, - - onRepeat: function() { - return $('#repeat').hasClass('active'); - }, - - updateNowListening: function(artist, album, track) { - if (Settings.user.lastfm_username) { - Session.query('/lastfm/listening?r='+ Math.random(), {'artist': artist, 'album': album, 'track': track}); - } - }, - - scrobble: function(artist, album, track) { - if (Settings.user.lastfm_username) { - Session.query('/lastfm/scrobble?r='+ Math.random(), {'artist': artist, 'album': album, 'track': track}); - } - } -} - -$(function(){ - Player.initJplayer(); -}); - -$('#player .controls .prev').live('click', function(){ - Player.setTrack(Player.prevTrack()); -}); - -$('#player .controls .next').live('click', function(){ - Player.setTrack(Player.nextTrack(true)); -}); - -$('.add-album').live('click', function() { - var artist = $('.artist-info .name').html(); - var album = $(this).parent().parent().parent().find('h2.name').text().replace(/\s\([\d]{4}\)$/, ''); - $(this).parent().parent().parent().find('.tracklist li').each(function(i, item){ - var track_name = $(item).find('.trackname').html(); - var length = $(item).find('.length').html(); - Player.addTrack(artist, album, track_name, length); - }); -}) -$('.add-track').live('click', function(){ - var artist = $('.artist-info .name').html(); - var album = $(this).parent().parent().parent().parent().find('h2.name').text().replace(/\s\([\d]{4}\)$/, ''); - var track_name = $(this).parent().find('.trackname').html(); - var length = $(this).parent().find('.length').html(); - Player.addTrack(artist, album, track_name, length); -}); - -$('#player .play').live('click', function(){ - if ($('.playlist-tracks li').length > 0 && !Player.hasTrack()) { - Player.setTrack($('.playlist-tracks li').first().attr('id').split('i')[1]); - } -}); - -$('.tracklist li').live('mouseover mouseout', function(e){ - if (e.type == 'mouseover') { - $(this).find('.add-track').show(); - } else { - $(this).find('.add-track').hide(); - } -}).live('dblclick', function(e){ - var artist = $('.artist-info .name').html(); - var album = $(this).parent().parent().parent().find('h2.name').text().replace(/\s\([\d]{4}\)$/, ''); - var track_name = $(this).find('.trackname').html(); - var length = $(this).find('.length').html(); - Player.addTrack(artist, album, track_name, length, true); -}); - -$('.playlist-tracks li .fade, .playlist-tracks li .duration, .playlist-tracks li .remove').live('mouseover mouseout', function(e){ - if (e.type == 'mouseover') { - $(this).parent().find('.duration').hide(); - $(this).parent().find('.remove').show(); - } else { - $(this).parent().find('.remove').hide(); - $(this).parent().find('.duration').show(); - } -}); - -$('.playlist-tracks li .remove').live('click', function(){ - var $li = $(this).parent().parent(); - if ($li.hasClass('now')) { - $('#jplayer').jPlayer('clearMedia'); - $('#player .now-playing').text('...'); - $('#player .loaded, #player .played').width(0); - } - $li.remove(); -}); - -$('.playlist-tracks li').live('dblclick', function(){ - Player.setTrack($(this).attr('id').split('i')[1]); -}); - -$('#player .progress').live('click', function(e){ - $('#jplayer').jPlayer('playHead', Math.round((e.offsetX / Player.bar_width) * 100)); -}); - -$('#repeat, #shuffle').live('click', function(){ - $(this).toggleClass('active'); -}); - -$('#empty-playlist').live('click', function(){ - if (confirm('Are you sure?')) { - $('.playlist-tracks li').remove(); - $('#jplayer').jPlayer('clearMedia'); - $('#player .now-playing').text('Add some music to playlist'); - $('#player .loaded, #player .played').width(0); - } -}); \ No newline at end of file diff --git a/public/js/beathaven/search.js b/public/js/beathaven/search.js deleted file mode 100644 index 47ac40b..0000000 --- a/public/js/beathaven/search.js +++ /dev/null @@ -1,71 +0,0 @@ -var Search = { - - pics: [], - - showSpinner: function() { - $('.search-container input').attr('disabled', 'disabled').blur(); - $('.search-container img').show(); - $('.autocomplete-container').hide(); - $('.artist_loading.failed').hide(); - Search.hideSuggestions(); - }, - - hideSpinner: function() { - $('.search-container input').removeAttr('disabled'); - $('.search_field').focus(); - $('.search-container img').hide(); - }, - - showSuggestions: function(values) { - for (var i = 0; i < values.length; i++) { - $('.suggestions ul').append('\ -
  • \ - '+ values[i].name +'\ - '+ (values[i].desc ? '
    '+ values[i].desc +'' : '') +'\ -
  • \ - '); - } - $('.suggestions').show(); - }, - - hideSuggestions: function() { - $('.suggestions ul li').remove(); - $('.suggestions').hide(); - }, - - showArtistPics: function(pics) { - $('.artist_loading.ok, .artist_pics').show(); - for (var i = 0; i < pics.length; i++) { - if (Search.pics.indexOf(pics[i]) === -1) { - Search.pics.push(pics[i]); - $('.artist_pics').append('\ -
    \ - \ -
    \ - '); - } - } - }, - - showError: function() { - $('.artist_loading.ok, .artist_pics').hide(); - $('.artist_loading.failed').show(); - Search.pics = [] - } -} - -$(function(){ - $('.search').live('click', function(){ - Ajax.loadSearchPage(); - return false; - }); - $('#search_form').live('submit', function(){ - $('.autocomplete-container').remove(); - Ajax.loadArtistData($('#search_field').val()); - return false; - }); - $('.suggestions a').live('click', function(){ - $('#search_field').val($(this).text()); - return false; - }); -}); \ No newline at end of file diff --git a/public/js/beathaven/session.js b/public/js/beathaven/session.js deleted file mode 100644 index 1fb5d64..0000000 --- a/public/js/beathaven/session.js +++ /dev/null @@ -1,20 +0,0 @@ -var Session = { - - user_id: null, - vk_params: {}, - - query: function(url, params, callback) { - var q_params = this.vk_params; - for (attr in params) { - q_params[attr] = params[attr]; - } - $.post(url, q_params, callback); - }, - - setVkParams: function(params) { - attrs = ['expire', 'mid', 'secret', 'sid', 'sig']; - for (var i = 0; i < attrs.length; i++) { - this.vk_params[attrs[i]] = params[attrs[i]]; - } - } -} \ No newline at end of file diff --git a/public/js/beathaven/settings.js b/public/js/beathaven/settings.js deleted file mode 100644 index 892a159..0000000 --- a/public/js/beathaven/settings.js +++ /dev/null @@ -1,53 +0,0 @@ -var Settings = { - - user: null, - - getAccountInfo: function(callback) { - Session.query('/user/update', {}, callback); - }, - - saveAccountInfo: function(params, callback) { - Session.query('/user/update', params, callback); - }, - - loadFormData: function(form) { - if (form == 'account') { - $('.settings-container .form input[name$="username"]').val(Settings.user.name); - $('.settings-container .form input[name$="email"]').val(Settings.user.email); - } else if (form == 'lastfm') { - if (Settings.user.lastfm_username) { - $('.form-container input[name$="username"]').first().val(Settings.user.lastfm_username); - } - } - } -} - -$('.settings').live('click', function() { - Ajax.loadSettingsPage(); -}); - -$('.settings-container .tabs .tab').live('click', function(){ - if (!$(this).hasClass('active')) { - $('.settings-container .tabs .tab').removeClass('active'); - $(this).addClass('active'); - $('.form-container').html($('.forms .'+ $(this).attr('data-fieldset')).html()); - Settings.loadFormData($(this).attr('data-fieldset')); - } -}); - -$('.lastfm-connect').live('click', function(){ - window.open(Settings.user.lastfm_login_url); -}); - -$('.settings-container .form input').live('blur', function(){ - var active_tab = $('.settings-container .tabs .tab.active').attr('data-fieldset'); - if (active_tab == 'account') { - params = { - 'username': $('.settings-container .form input[name$="username"]').first().val(), - 'email': $('.settings-container .form input[name$="email"]').first().val(), - }; - Settings.saveAccountInfo(params, function(){ - $('#header-container .hello .greating').text('Hi there, '+ (params.username.length > 0 ? params.username : '%username%') +'!'); - }); - } -}) \ No newline at end of file diff --git a/public/js/beathaven/vkontakte.js b/public/js/beathaven/vkontakte.js deleted file mode 100644 index 0ae899c..0000000 --- a/public/js/beathaven/vkontakte.js +++ /dev/null @@ -1,102 +0,0 @@ -var Vkontakte = { - - qr: [], - - authInfo: function(response) { - if (typeof response != 'undefined' && response.session) { - Session.setVkParams(response.session); - $('#vk_login, .auth_notice').hide(); - $('#vk_logout').css('display', 'block'); - if ($('#search_field').length > 0) { - $('#search_field').focus(); - } - Session.query('/user/auth', {}, function(ar){ - if (ar.newbie) { - VK.Api.call('getVariable', {key: 1281}, function(r) { - Session.query('/user/update', {'name': r.response}, function(ar2) { - Settings.user = ar2.user; - $('#header-container .hello .greating').text('Hi there, '+ (Settings.user.name ? Settings.user.name : '%username%') +'!'); - }); - }); - } else { - Settings.user = ar.user; - } - $('#header-container .hello .greating').text('Hi there, '+ (Settings.user.name ? Settings.user.name : '%username%') +'!'); - }); - } else { - $('#vk_login, .auth_notice').css('display', 'block'); - $('#vk_logout').hide(); - } - }, - - loadTracksData: function(artist, track, duration, callback) { - var track_prepared = track.replace(/\(.*\)/i, '').split('/')[0]; - var query = artist +' '+ track_prepared; - if (typeof Vkontakte.qr[query] !== 'undefined') { - callback(Vkontakte.qr[query]); - } else { - VK.Api.call('audio.search', {q: query}, function(r){ - var url = Vkontakte.matchPerfectResult(r.response, artist, track, duration); - Vkontakte.qr[query] = url; - callback(url); - }); - } - }, - - matchPerfectResult: function(data, artist, track, duration) { - var duration = duration.split(':'); - if (duration[1].charAt(0) === '0') { - duration[1] = duration[1].substring(1); - } - duration = parseInt(duration[0]) * 60 + parseInt(duration[1]); - var best_score = 0; - var best_result = null; - for (var i = 1; i < data.length; i++) { - var score = 0; - data[i].artist = data[i].artist.trim(); - data[i].title = data[i].title.trim(); - if (data[i].artist === artist) { - score += 10; - } else if (data[i].artist.split(artist).length === 2) { - score += 5; - } else if (data[i].title.split(artist).length === 2) { - score += 4; - } - if (data[i].title === track) { - score += 10; - } else if (data[i].title.split(track).length === 2) { - score += 5; - } - if (parseInt(data[i].duration) === duration) { - score += 15; - } else { - var delta = Math.abs(parseInt(data[i].duration) - duration); - if (delta < 10) { - score += (10 - delta); - } - } - if (score > best_score) { - best_score = score; - best_result = data[i]; - } - if (score === 35) { - return best_result.url; - } - } - return best_result.url; - } -} - -$(function(){ - VK.init({ - apiId: (document.location.host == 'beathaven.org' ? 2335068 : 2383163), - nameTransportPath: "/xd_receiver.html" - }); - VK.Auth.getLoginStatus(Vkontakte.authInfo); - $('#vk_login').click(function(){ - VK.Auth.login(Vkontakte.authInfo, 8); - }); - $('#vk_logout').click(function(){ - VK.Auth.logout(Vkontakte.authInfo); - }); -}) \ No newline at end of file diff --git a/public/stylesheets/.gitkeep b/public/stylesheets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/public/css/_sass/_alpha_gradient.scss b/public/stylesheets/_sass/_alpha_gradient.scss similarity index 100% rename from public/css/_sass/_alpha_gradient.scss rename to public/stylesheets/_sass/_alpha_gradient.scss diff --git a/public/css/_sass/_opacity.scss b/public/stylesheets/_sass/_opacity.scss similarity index 100% rename from public/css/_sass/_opacity.scss rename to public/stylesheets/_sass/_opacity.scss diff --git a/public/css/_sass/_rounded.scss b/public/stylesheets/_sass/_rounded.scss similarity index 100% rename from public/css/_sass/_rounded.scss rename to public/stylesheets/_sass/_rounded.scss diff --git a/public/css/_sass/albums.scss b/public/stylesheets/_sass/albums.scss similarity index 100% rename from public/css/_sass/albums.scss rename to public/stylesheets/_sass/albums.scss diff --git a/public/css/_sass/common.scss b/public/stylesheets/_sass/common.scss similarity index 100% rename from public/css/_sass/common.scss rename to public/stylesheets/_sass/common.scss diff --git a/public/css/_sass/header.scss b/public/stylesheets/_sass/header.scss similarity index 100% rename from public/css/_sass/header.scss rename to public/stylesheets/_sass/header.scss diff --git a/public/css/_sass/misc.scss b/public/stylesheets/_sass/misc.scss similarity index 100% rename from public/css/_sass/misc.scss rename to public/stylesheets/_sass/misc.scss diff --git a/public/css/_sass/player.scss b/public/stylesheets/_sass/player.scss similarity index 100% rename from public/css/_sass/player.scss rename to public/stylesheets/_sass/player.scss diff --git a/public/css/_sass/search.scss b/public/stylesheets/_sass/search.scss similarity index 100% rename from public/css/_sass/search.scss rename to public/stylesheets/_sass/search.scss diff --git a/public/css/_sass/settings.scss b/public/stylesheets/_sass/settings.scss similarity index 100% rename from public/css/_sass/settings.scss rename to public/stylesheets/_sass/settings.scss diff --git a/public/css/albums.css b/public/stylesheets/albums.css similarity index 100% rename from public/css/albums.css rename to public/stylesheets/albums.css diff --git a/public/css/beathaven.css b/public/stylesheets/beathaven.css similarity index 100% rename from public/css/beathaven.css rename to public/stylesheets/beathaven.css diff --git a/public/css/common.css b/public/stylesheets/common.css similarity index 100% rename from public/css/common.css rename to public/stylesheets/common.css diff --git a/public/css/header.css b/public/stylesheets/header.css similarity index 100% rename from public/css/header.css rename to public/stylesheets/header.css diff --git a/public/css/misc.css b/public/stylesheets/misc.css similarity index 100% rename from public/css/misc.css rename to public/stylesheets/misc.css diff --git a/public/css/player.css b/public/stylesheets/player.css similarity index 100% rename from public/css/player.css rename to public/stylesheets/player.css diff --git a/public/css/search.css b/public/stylesheets/search.css similarity index 100% rename from public/css/search.css rename to public/stylesheets/search.css diff --git a/public/css/settings.css b/public/stylesheets/settings.css similarity index 100% rename from public/css/settings.css rename to public/stylesheets/settings.css