From 9f770892f8c4940de790d5fea1d348661435e248 Mon Sep 17 00:00:00 2001 From: Gregory Eremin Date: Sun, 2 Sep 2012 02:03:19 +0400 Subject: [PATCH] The player is playing! --- Gemfile | 25 +++---- Gemfile.lock | 10 ++- app/assets/javascripts/application.js | 15 +--- .../backbone/autocomplete.js.coffee | 4 +- .../javascripts/backbone/beat_haven.js.coffee | 22 ++++-- .../backbone/models/player.js.coffee | 53 ++++++++++++++ .../backbone/models/track.js.coffee | 38 +++++++++- .../backbone/models/user.js.coffee | 27 +++++++ .../javascripts/backbone/models/vk.js.coffee | 43 +++++++++++ .../backbone/templates/album/show.mustache | 1 + .../backbone/templates/artist/show.mustache | 1 + .../backbone/views/album/album_show.js.coffee | 2 +- .../views/artist/artist_show.js.coffee | 2 +- .../javascripts/bindings/auth.js.coffee | 7 ++ .../javascripts/bindings/player.js.coffee | 9 +++ .../javascripts/bindings/track.js.coffee | 5 ++ app/assets/stylesheets/album-track.css.scss | 24 ++++++- app/assets/stylesheets/application.css.scss | 5 ++ app/assets/stylesheets/auth.css.scss | 3 + app/assets/stylesheets/player.css.scss | 7 +- app/controllers/api/session_controller.rb | 36 ++++++++++ app/models/user.rb | 12 ++++ app/views/application/_player.html.erb | 13 ++++ app/views/layouts/application.html.erb | 18 ++--- .../{beatparser.rb => api_accounts.rb} | 1 + config/routes.rb | 3 + db/migrate/20120901191655_create_users.rb | 11 +++ db/schema.rb | 10 ++- vendor/assets/javascripts/vk_music.js.coffee | 72 +++++++++++++++++++ 29 files changed, 422 insertions(+), 57 deletions(-) create mode 100644 app/assets/javascripts/backbone/models/user.js.coffee create mode 100644 app/assets/javascripts/backbone/models/vk.js.coffee create mode 100644 app/assets/javascripts/bindings/auth.js.coffee create mode 100644 app/assets/javascripts/bindings/player.js.coffee create mode 100644 app/assets/javascripts/bindings/track.js.coffee create mode 100644 app/assets/stylesheets/auth.css.scss create mode 100644 app/controllers/api/session_controller.rb create mode 100644 app/models/user.rb create mode 100644 app/views/application/_player.html.erb rename config/initializers/{beatparser.rb => api_accounts.rb} (85%) create mode 100644 db/migrate/20120901191655_create_users.rb create mode 100644 vendor/assets/javascripts/vk_music.js.coffee diff --git a/Gemfile b/Gemfile index 69c3a2e..e57f43e 100644 --- a/Gemfile +++ b/Gemfile @@ -2,30 +2,31 @@ source :rubygems gem "rails", "3.2.8" gem "pg" +gem "thin" group :assets do gem "sass-rails", "~> 3.2.3" gem "coffee-rails", "~> 3.2.1" - gem "therubyracer", platforms: :ruby - gem "hogan_assets" - gem "uglifier", ">= 1.0.3" + + gem "jquery-rails" + gem "rails-backbone" + gem "hogan_assets" gem "bourbon" + gem "bootstrap-sass", "~> 2.0.4.0" + gem "soundmanager-rails" end -gem "jquery-rails" +group :development do + gem "awesome_print", require: "ap" + + # Deploy with Capistrano + gem "capistrano" +end # To use Jbuilder templates for JSON gem "jbuilder" -gem "thin" - -# Deploy with Capistrano -gem "capistrano" - gem "robbie", path: "../robbie" gem "beatparser", path: "../beatparser" -gem "rails-backbone" -gem "eco" -gem 'bootstrap-sass', '~> 2.0.4.0' diff --git a/Gemfile.lock b/Gemfile.lock index e70c918..649eeb8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -44,6 +44,7 @@ GEM i18n (~> 0.6) multi_json (~> 1.0) arel (3.0.2) + awesome_print (1.0.2) blankslate (2.1.2.4) bootstrap-sass (2.0.4.0) bourbon (2.1.1) @@ -63,11 +64,6 @@ GEM execjs coffee-script-source (1.3.3) daemons (1.1.9) - eco (1.0.0) - coffee-script - eco-source - execjs - eco-source (1.1.0.rc.1) ejs (1.0.0) erubis (2.7.0) eventmachine (0.12.10) @@ -148,6 +144,7 @@ GEM railties (~> 3.2.0) sass (>= 3.1.10) tilt (~> 1.3) + soundmanager-rails (0.1.1) sprockets (2.1.3) hike (~> 1.2) rack (~> 1.0) @@ -172,12 +169,12 @@ PLATFORMS ruby DEPENDENCIES + awesome_print beatparser! bootstrap-sass (~> 2.0.4.0) bourbon capistrano coffee-rails (~> 3.2.1) - eco hogan_assets jbuilder jquery-rails @@ -186,6 +183,7 @@ DEPENDENCIES rails-backbone robbie! sass-rails (~> 3.2.3) + soundmanager-rails therubyracer thin uglifier (>= 1.0.3) diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 1eb0aed..90c9df1 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -1,18 +1,8 @@ -// This is a manifest file that'll be compiled into application.js, which will include all the files -// listed below. -// -// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, -// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. -// -// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the -// the compiled file. -// -// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD -// GO AFTER THE REQUIRES BELOW. -// //= require jquery //= require jquery_ujs //= require jquery.autocomplete +//= require soundmanager +//= require vk_music //= require mustache //= require hogan //= require underscore @@ -20,5 +10,6 @@ //= require backbone_rails_sync //= require backbone_datalink //= require backbone/beat_haven +//= require bootstrap-dropdown //= require_tree . diff --git a/app/assets/javascripts/backbone/autocomplete.js.coffee b/app/assets/javascripts/backbone/autocomplete.js.coffee index 3da2d2b..d8c437f 100644 --- a/app/assets/javascripts/backbone/autocomplete.js.coffee +++ b/app/assets/javascripts/backbone/autocomplete.js.coffee @@ -1,10 +1,10 @@ $ -> $(".navbar-search input").focus -> $(this).animate(width: 249) - $(".player").animate(width: 408) + $(".player").animate(width: 368) $(".navbar-search input").blur -> $(this).animate(width: 99) - $(".player").animate(width: 558) + $(".player").animate(width: 518) window.desired = $(".navbar-search input").autocomplete serviceUrl: "/api/search/complete" diff --git a/app/assets/javascripts/backbone/beat_haven.js.coffee b/app/assets/javascripts/backbone/beat_haven.js.coffee index bcbec4a..6b6e2bf 100644 --- a/app/assets/javascripts/backbone/beat_haven.js.coffee +++ b/app/assets/javascripts/backbone/beat_haven.js.coffee @@ -9,24 +9,32 @@ window.BeatHaven = Collections: {} Routers: {} Views: {} - player: null + + Player: null + User: null init: -> new BeatHaven.Routers.Artist() new BeatHaven.Routers.Album() new BeatHaven.Routers.Search() - @player = new BeatHaven.Models.Player() + @Player = new BeatHaven.Models.Player() + @User = new BeatHaven.Models.User() + @VK = new BeatHaven.Models.VK() + + @VK.init() Backbone.history.start(pushState: true); $("a").live "click", (e) -> if $(this).attr("href").substr(0, 1) == "/" e.preventDefault() Backbone.history.navigate($(this).attr("href"), true) - return false - else - alert "Window close attempt!" - return false - true + false + + log: (data) -> + console.log data $ -> BeatHaven.init() + +# Setup shortcut +window.BH = window.BeatHaven diff --git a/app/assets/javascripts/backbone/models/player.js.coffee b/app/assets/javascripts/backbone/models/player.js.coffee index cf1799f..d250e73 100644 --- a/app/assets/javascripts/backbone/models/player.js.coffee +++ b/app/assets/javascripts/backbone/models/player.js.coffee @@ -2,10 +2,63 @@ class BeatHaven.Models.Player extends Backbone.Model playlist_on: false playlist: null tracks: null + current_track: null initialize: -> @playlist = new BeatHaven.Collections.Tracklist() @tracks = new BeatHaven.Collections.Tracklist() + play: (track) -> + unless track? + if @current_track? + @current_track.get("sm_obj").resume() + else + this.play_something() + else + if @current_track? + @current_track.get("sm_obj").stop() + $(".player .progress-bar .bar").css(width: 0) + @current_track = track + @current_track.get("sm_obj").play() + $(".player .controls .play").css(display: "none") + $(".player .controls .pause").css(display: "inline-block") + + pause: -> + return false unless @current_track? + @current_track.get("sm_obj").pause() + $(".player .controls .play").css(display: "inline-block") + $(".player .controls .pause").css(display: "none") + + next: -> + return false unless @current_track? + if @playlist_on + # not implemented + else + nodes = @current_track.node().next() + return false unless nodes.length == 1 + @tracks.get(parseInt($(nodes[0]).data("id"), 10)).play() + + prev: -> + return false unless @current_track? + if @playlist_on + # not implemented + else + nodes = @current_track.node().prev() + return false unless nodes.length == 1 + @tracks.get(parseInt($(nodes[0]).data("id"), 10)).play() + + play_something: -> + nodes = $(".artist-page .tracks li[data-id]") + return false unless nodes.length > 0 + @tracks.get(parseInt($(nodes[0]).data("id"), 10)).play() + update_title: (params) -> $(".player .progress-bar .title").html("#{params.artists.join(', ')} — #{params.track}") + + update_buffer_bar: (event) -> + false + + update_progress_bar: (obj) -> + percent = obj.position / obj.duration * 100 + $(".player .progress-bar .bar").css(width: "#{percent}%") + diff --git a/app/assets/javascripts/backbone/models/track.js.coffee b/app/assets/javascripts/backbone/models/track.js.coffee index b5c0f9c..3cf9be6 100644 --- a/app/assets/javascripts/backbone/models/track.js.coffee +++ b/app/assets/javascripts/backbone/models/track.js.coffee @@ -1,7 +1,43 @@ class BeatHaven.Models.Track extends Backbone.Model play: -> - BeatHaven.player.update_title( + if @.get("sm_obj")? + this.start() + else + this.find_and_start() + + start: -> + BH.Player.update_title( artists: @.get("artists") track: @.get("title") ) + unless @.get("sm_obj")? + this.add_to_library(autoload: true, autoplay: false) + BH.Player.play(this) + $(".artist-page .tracks li[data-id]").removeClass("now-playing") + this.node().addClass("now-playing") + + find_and_start: -> + self = this + BH.VK.Music.search @.get("artists")[0], @.get("title"), @.get("length"), (url) -> + self.set(url: url) + self.start() + + add_to_library: (params) -> + obj = soundManager.createSound + id: @.get("id") + url: @.get("url") + autoLoad: params.autoload + autoPlay: params.autoplay + whileloading: -> + BH.Player.update_buffer_bar(this) + whileplaying: -> + BH.Player.update_progress_bar(this) + onfinish: -> + BH.Player.next() + ondataerror: -> + BH.Player.next() + @.set("sm_obj", obj) + + node: -> + $(".artist-page .tracks li[data-id='#{@.get("id")}']") diff --git a/app/assets/javascripts/backbone/models/user.js.coffee b/app/assets/javascripts/backbone/models/user.js.coffee new file mode 100644 index 0000000..35fbc2e --- /dev/null +++ b/app/assets/javascripts/backbone/models/user.js.coffee @@ -0,0 +1,27 @@ +class BeatHaven.Models.User extends Backbone.Model + + auth: -> + BH.log "Authenticating user ..." + this.query "/api/session/auth", {}, (response) -> + if response.error? + # report error + else + BH.User.set(JSON.parse(response.user)) + if response.is_newbie + BH.log "Requesting user tracks from Vkontakte ..." + # BH.VK.set_favorites() + + query: (path, params, callback) -> + query_params = $.extend {}, @.get("vk_session"), params + query_params.authenticity_token = $('meta[name="csrf-token"]').attr("content") + $.post path, query_params, callback + false + + set_favorites: (tracks) -> + BH.log tracks + BH.log "Sending your Vkontakte media collection to BeatHaven ..." + this.query "/user/set_first_favorites", tracks: tracks, (response) -> + if response.error? + BH.log "Got error: #{response.error}" + else + BH.log "We believe your favorite artists are #{response.join(', ')}" diff --git a/app/assets/javascripts/backbone/models/vk.js.coffee b/app/assets/javascripts/backbone/models/vk.js.coffee new file mode 100644 index 0000000..364ea65 --- /dev/null +++ b/app/assets/javascripts/backbone/models/vk.js.coffee @@ -0,0 +1,43 @@ +class BeatHaven.Models.VK extends Backbone.Model + + session_length: 3600 # seconds + Music: null + + popup: -> + alert(1) + + init: -> + @Music = new VkMusic() + BH.log "Initializing Vkontakte API ..." + window.VK.init(apiId: VK_APP_ID) + BH.VK.auth() + # VK.Widgets.Like("vk-like", {type: "mini", height: 20, pageUrl: "http://beathaven.org/", text: "Like"}) + + auth: -> + BH.log "Requesting new Vkontakte session ..." + window.VK.Auth.getLoginStatus (response) -> + BH.VK.auth_info(response) + false + , 8 + false + + auth_info: (response) -> + if typeof response isnt "undefined" and response.session? + BH.User.set(vk_session: response.session) + BH.User.auth() + + if response.session.expire? + expire_in = response.session.expire * 1000 - new Date().getTime() + # time is an illusion... + expire_in = @session_length * 1000 + BH.log "Session will expire in #{Math.round(expire_in / 1000)} seconds" + setTimeout -> + BH.log "Session expired" + BH.VK.auth() + , expire_in + 1000 + else + BH.log "Not authorized" + + set_favorites: -> + window.VK.Api.call "audio.get", uid: BH.User.vk_id(), (response) -> + BH.User.set_favorites(response.response) diff --git a/app/assets/javascripts/backbone/templates/album/show.mustache b/app/assets/javascripts/backbone/templates/album/show.mustache index 17ab256..92e4801 100644 --- a/app/assets/javascripts/backbone/templates/album/show.mustache +++ b/app/assets/javascripts/backbone/templates/album/show.mustache @@ -10,6 +10,7 @@ {{#album_tracks}}
  • +
    {{track_title}} diff --git a/app/assets/javascripts/backbone/templates/artist/show.mustache b/app/assets/javascripts/backbone/templates/artist/show.mustache index f453307..3030d1d 100644 --- a/app/assets/javascripts/backbone/templates/artist/show.mustache +++ b/app/assets/javascripts/backbone/templates/artist/show.mustache @@ -23,6 +23,7 @@ {{#album_tracks}}
  • +
    {{track_title}} diff --git a/app/assets/javascripts/backbone/views/album/album_show.js.coffee b/app/assets/javascripts/backbone/views/album/album_show.js.coffee index 365c163..ad9f4e0 100644 --- a/app/assets/javascripts/backbone/views/album/album_show.js.coffee +++ b/app/assets/javascripts/backbone/views/album/album_show.js.coffee @@ -8,6 +8,6 @@ class BeatHaven.Views.AlbumShow extends Backbone.View if typeof @model.get("album_tracks") != "undefined" for track_info in @model.get("album_tracks") track = new BeatHaven.Models.Track(track_info.meta) - BeatHaven.player.tracks.push(track) + BeatHaven.Player.tracks.push(track) $(@el).html(@template.render(@model.toJSON())) this diff --git a/app/assets/javascripts/backbone/views/artist/artist_show.js.coffee b/app/assets/javascripts/backbone/views/artist/artist_show.js.coffee index 457d39b..ae8f200 100644 --- a/app/assets/javascripts/backbone/views/artist/artist_show.js.coffee +++ b/app/assets/javascripts/backbone/views/artist/artist_show.js.coffee @@ -9,6 +9,6 @@ class BeatHaven.Views.ArtistShow extends Backbone.View for album_info in @model.get("artist_albums") for track_info in album_info.album_tracks track = new BeatHaven.Models.Track(track_info.meta) - BeatHaven.player.tracks.push(track) + BeatHaven.Player.tracks.push(track) $(@el).html(@template.render(@model.toJSON())) this diff --git a/app/assets/javascripts/bindings/auth.js.coffee b/app/assets/javascripts/bindings/auth.js.coffee new file mode 100644 index 0000000..1aaf8a0 --- /dev/null +++ b/app/assets/javascripts/bindings/auth.js.coffee @@ -0,0 +1,7 @@ +$ -> + $(".auth a").bind "mouseup", (e) -> + e.preventDefault() + if BeatHaven.authenticated + alert("auth ok!!!!!") + else + BeatHaven.VK.popup() diff --git a/app/assets/javascripts/bindings/player.js.coffee b/app/assets/javascripts/bindings/player.js.coffee new file mode 100644 index 0000000..9d6cec3 --- /dev/null +++ b/app/assets/javascripts/bindings/player.js.coffee @@ -0,0 +1,9 @@ +$ -> + $(".player .controls .prev").live "click", (e) -> + BH.Player.prev() + $(".player .controls .play").live "click", (e) -> + BH.Player.play() + $(".player .controls .pause").live "click", (e) -> + BH.Player.pause() + $(".player .controls .next").live "click", (e) -> + BH.Player.next() diff --git a/app/assets/javascripts/bindings/track.js.coffee b/app/assets/javascripts/bindings/track.js.coffee new file mode 100644 index 0000000..07ef850 --- /dev/null +++ b/app/assets/javascripts/bindings/track.js.coffee @@ -0,0 +1,5 @@ +$ -> + $(".track-play").live "click", (e) -> + e.preventDefault() + id = parseInt($(this).parent().data("id"), 10) + BH.Player.tracks.get(id).play() diff --git a/app/assets/stylesheets/album-track.css.scss b/app/assets/stylesheets/album-track.css.scss index 49e83b6..cb7c15e 100644 --- a/app/assets/stylesheets/album-track.css.scss +++ b/app/assets/stylesheets/album-track.css.scss @@ -24,6 +24,23 @@ display: none; } + &.now-playing { + a { + color: #126be8 !important; + text-shadow: 0 0 1px rgba(255, 255, 255, .2); + } + .track-play { + display: none; + } + .track-pause { + display: block; + + i { + opacity: 1; + } + } + } + .btn-round { width: 10px; height: 22px; @@ -34,7 +51,7 @@ } } - .track-play { + .track-play, .track-pause { position: absolute; top: 3px; left: 5px; @@ -43,6 +60,9 @@ opacity: .3; } } + .track-pause { + display: none; + } // Track title .title { @@ -112,7 +132,7 @@ } background-color: rgba(200, 200, 200, .3); - .track-play i { + .track-play i, .track-pause i { opacity: 1; } .track-add { diff --git a/app/assets/stylesheets/application.css.scss b/app/assets/stylesheets/application.css.scss index 7c7c176..01f5029 100644 --- a/app/assets/stylesheets/application.css.scss +++ b/app/assets/stylesheets/application.css.scss @@ -6,6 +6,7 @@ @import "artist"; @import "album-track"; @import "player"; +@import "auth"; @import url(http://fonts.googleapis.com/css?family=Lobster+Two:400,400italic,700); @import url(http://fonts.googleapis.com/css?family=Source+Sans+Pro); @@ -25,6 +26,10 @@ body { .navbar-inner { background: none; @include background-image(linear-gradient(rgba(0, 0, 0, .05) 0, rgba(0, 0, 0, .4) 100%)); + + .container { + overflow: hidden; + } } a.brand { margin-top: 1px; diff --git a/app/assets/stylesheets/auth.css.scss b/app/assets/stylesheets/auth.css.scss new file mode 100644 index 0000000..545b58e --- /dev/null +++ b/app/assets/stylesheets/auth.css.scss @@ -0,0 +1,3 @@ +.navbar .auth { + margin: 14px 10px 0 15px; +} diff --git a/app/assets/stylesheets/player.css.scss b/app/assets/stylesheets/player.css.scss index b228953..279fff7 100644 --- a/app/assets/stylesheets/player.css.scss +++ b/app/assets/stylesheets/player.css.scss @@ -1,5 +1,5 @@ .player { - width: 558px; + width: 518px; .controls { float: left; @@ -8,6 +8,10 @@ a { margin: 5px 6px 0 -9px; } + + .pause { + display: none; + } } .progress-bar { position: relative; @@ -25,6 +29,7 @@ .bar { position: absolute; + width: 0%; height: 26px; background-color: rgba(255, 255, 255, .1); @include box-shadow(inset 0 0 2px rgba(255, 255, 255, .2)); diff --git a/app/controllers/api/session_controller.rb b/app/controllers/api/session_controller.rb new file mode 100644 index 0000000..7179273 --- /dev/null +++ b/app/controllers/api/session_controller.rb @@ -0,0 +1,36 @@ +module Api + class SessionController < ApplicationController + + def auth + render json: { error: "Signature verification failed!" } unless request_valid? + + user_name = "#{params[:user][:first_name]} #{params[:user][:last_name]}" + + user = User.find_by_vk_id(params[:mid].to_i) + is_newbie = false + if user.nil? + user = User.create(name: user_name, vk_id: params[:mid].to_i) + is_newbie = true + elsif user.name != user_name + user.update_attributes(name: user_name) + end + + render json: { user: user.dump_json, is_newbie: is_newbie } + end + + private + + def request_valid? + %w[ expire mid secret sid sig ].map(&:to_sym).each do |key| + raise "Parameter not set: #{key}" if params[key].nil? + end + + validation_string = %w[ expire mid secret sid ].map{ |key| + "#{key}=#{params[key.to_sym]}" + }.join() << BeatHaven::Application.config.api_accounts["vk"]["api_secret"] + + params[:sig] == Digest::MD5.hexdigest(validation_string) + end + + end +end diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..8795494 --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,12 @@ +class User < ActiveRecord::Base + attr_accessible :lang, :name, :vk_id + + def dump_json + Jbuilder.encode do |j| + j.id id + j.name name + j.lang lang + j.vk_id vk_id + end + end +end diff --git a/app/views/application/_player.html.erb b/app/views/application/_player.html.erb new file mode 100644 index 0000000..774eb8d --- /dev/null +++ b/app/views/application/_player.html.erb @@ -0,0 +1,13 @@ +
    +
    + + + + +
    +
    +
    +
    Waiting...
    +
    +
    +
    diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 78a2fbc..bc51136 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -4,7 +4,11 @@ BeatHaven <%= stylesheet_link_tag "application", media: "all" %> <%= javascript_include_tag "application" %> + <%= javascript_include_tag "http://vkontakte.ru/js/api/openapi.js" %> <%= csrf_meta_tags %> + @@ -15,18 +19,10 @@ -
    -
    - - - -
    -
    -
    -
    Foo Fighters — Alone + Easy Target
    -
    -
    +
    +
    + <%= render partial: "player" %>
    diff --git a/config/initializers/beatparser.rb b/config/initializers/api_accounts.rb similarity index 85% rename from config/initializers/beatparser.rb rename to config/initializers/api_accounts.rb index 3657e51..0651168 100644 --- a/config/initializers/beatparser.rb +++ b/config/initializers/api_accounts.rb @@ -1,5 +1,6 @@ File.open("#{Rails.root}/config/api_keys.yml") do |file| config = YAML.load(file.read) + BeatHaven::Application.config.api_accounts = config LastFM.api_key = config["lastfm"]["api_key"] LastFM.secret = config["lastfm"]["api_secret"] diff --git a/config/routes.rb b/config/routes.rb index 7b9fd4f..810b53e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -7,6 +7,9 @@ BeatHaven::Application.routes.draw do resources :search, only: [] do collection { get :complete; get :wtfis } end + resources :session, only: [] do + collection { post :auth } + end end match "/:path" => "application#main", constraints: { path: /.*/ } diff --git a/db/migrate/20120901191655_create_users.rb b/db/migrate/20120901191655_create_users.rb new file mode 100644 index 0000000..7452870 --- /dev/null +++ b/db/migrate/20120901191655_create_users.rb @@ -0,0 +1,11 @@ +class CreateUsers < ActiveRecord::Migration + def change + create_table :users do |t| + t.string :name + t.integer :vk_id + t.string :lang, default: "ru" + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 1ce493d..6b9fb00 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20120901111329) do +ActiveRecord::Schema.define(:version => 20120901191655) do create_table "albums", :force => true do |t| t.integer "artist_id" @@ -66,4 +66,12 @@ ActiveRecord::Schema.define(:version => 20120901111329) do t.datetime "updated_at", :null => false end + create_table "users", :force => true do |t| + t.string "name" + t.integer "vk_id" + t.string "lang", :default => "ru" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + end diff --git a/vendor/assets/javascripts/vk_music.js.coffee b/vendor/assets/javascripts/vk_music.js.coffee new file mode 100644 index 0000000..90a5f9e --- /dev/null +++ b/vendor/assets/javascripts/vk_music.js.coffee @@ -0,0 +1,72 @@ +### + * Vkontakte (VK.com) API music search tool + * https://github.com/magnolia-fan/vkontakte_music_search + * + * Copyright 2011, Gregory Eremin + * Licensed under the MIT license. + * https://raw.github.com/magnolia-fan/vkontakte_music_search/master/LICENSE + ### + +class window.VkMusic + query_results: {} + + search: (artist, track, duration, callback, return_all = false) -> + query = this.prepareQuery artist, track + if @query_results[query]? and not return_all + callback @query_results[query] + that = this + VK.Api.call 'audio.search', q: query, (r) -> + results = that.range r.response, artist, track, duration + top_result = null + if results.length > 0 + top_result = results[0].url + that.query_results[query] = results + callback if return_all then results else top_result + + range: (data, artist, track, duration) -> + if typeof duration is 'string' + duration = duration.split ':' + duration = parseInt(duration[0], 10) * 60 + parseInt(duration[1], 10) + for item, i in data + if typeof item isnt 'object' + continue + item.score = 0 + item.artist = this.trim(item.artist) + item.title = this.trim(item.title) + score = 0 + if item.artist.length > 0 + 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.artist.length > 0 + if item.title == track + score += 10 + else if item.title.split(track).length is 2 + score += 5 + if duration != 0 and parseInt(item.duration, 10) == duration + score += 15 + else + delta = Math.abs parseInt(item.duration, 10) - duration + score += (10 - delta) if delta < 10 + data[i].score = score + if data.length > 0 + if typeof data[0] isnt 'object' + data.splice(0, 1) + data.sort (a, b) -> + b.score - a.score + data + + prepareQuery: (artist, track) -> + artist+" "+track.replace(/\(.*\)/i, '').split('/')[0] + + trim: (str) -> + while str.indexOf(' ') isnt -1 + str = str.replace(' ', ' ') + if str.charAt(0) is ' ' + str = str.substring(1) + if str.charAt(str.length - 1) is ' ' + str = str.substring(0, str.length - 1) + str