diff --git a/Gemfile b/Gemfile index 38d6027..86f6717 100644 --- a/Gemfile +++ b/Gemfile @@ -19,6 +19,7 @@ gem 'typhoeus' # for object caching gem 'redis' +gem 'redis-namespace' # for using 7digital api gem '7digital' diff --git a/Gemfile.lock b/Gemfile.lock index e930bc0..ebbb380 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -33,8 +33,10 @@ GEM activesupport (3.0.5) addressable (2.2.6) arel (2.0.10) + bcrypt-ruby (2.1.4) bcrypt-ruby (2.1.4-x86-mingw32) builder (2.1.2) + daemons (1.0.10) devise (1.3.4) bcrypt-ruby (~> 2.1.2) orm_adapter (~> 0.0.3) @@ -44,7 +46,7 @@ GEM faraday (0.6.1) addressable (~> 2.2.4) multipart-post (~> 1.1.0) - rack (>= 1.1.0, < 2) + rack (< 2, >= 1.1.0) gem_plugin (0.2.3) haml (3.1.2) haml-rails (0.3.4) @@ -64,6 +66,9 @@ GEM mime-types (~> 1.16) treetop (~> 1.4.8) mime-types (1.16) + mongrel (1.2.0.pre2) + daemons (~> 1.0.10) + gem_plugin (~> 0.2.3) mongrel (1.2.0.pre2-x86-mingw32) gem_plugin (~> 0.2.3) multi_json (1.0.3) @@ -114,6 +119,8 @@ GEM thor (~> 0.14.4) rake (0.9.2) redis (2.2.1) + redis-namespace (1.0.3) + redis (< 3.0.0) ruby-openid (2.1.8) ruby-openid-apps-discovery (1.2.0) ruby-openid (>= 2.1.7) @@ -121,6 +128,7 @@ GEM sexp_processor (~> 3.0) sass (3.1.2) sexp_processor (3.0.5) + sqlite3 (1.3.3) sqlite3 (1.3.3-x86-mingw32) sqlite3-ruby (1.3.3) sqlite3 (>= 1.3.3) @@ -139,6 +147,7 @@ GEM oauth (>= 0.4.4) PLATFORMS + ruby x86-mingw32 DEPENDENCIES @@ -155,6 +164,7 @@ DEPENDENCIES rails (= 3.0.5) rake redis + redis-namespace ruby_parser sass sqlite3 diff --git a/config/initializers/app_config.rb b/config/initializers/app_config.rb index c489a4c..e991df9 100644 --- a/config/initializers/app_config.rb +++ b/config/initializers/app_config.rb @@ -1 +1,4 @@ -APP_CONFIG = HashWithIndifferentAccess.new(YAML.load(File.open(File.join(Rails.root, 'config', 'config.yml')))) \ No newline at end of file +APP_CONFIG = HashWithIndifferentAccess.new(YAML.load(File.open(File.join(Rails.root, 'config', 'config.yml')))) + +require "sevendigital" +$sevendigital_client = Sevendigital::Client.new("config/sevendigital.yml", :country => "US") \ No newline at end of file diff --git a/config/initializers/redis.rb b/config/initializers/redis.rb new file mode 100644 index 0000000..75c6c6c --- /dev/null +++ b/config/initializers/redis.rb @@ -0,0 +1,8 @@ +$redis = Redis.new(:host => 'localhost', :port => 6379) + +begin + $redis.ping + puts "=> Established connection to redis server" +rescue + puts "=> CAUTION: cound not establish connection to redis server! Check settings in initializer!" +end \ No newline at end of file diff --git a/config/initializers/sevendigital.rb b/config/initializers/sevendigital.rb index 0de5f5f..d88856a 100644 --- a/config/initializers/sevendigital.rb +++ b/config/initializers/sevendigital.rb @@ -1 +1 @@ -require "sevendigital" $sevendigital_client = Sevendigital::Client.new("config/sevendigital.yml", :country => "US") \ No newline at end of file +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # currently moved to app_config.rb because of inexplicable problems on Mac OSX # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # require "sevendigital" # $sevendigital_client = Sevendigital::Client.new("config/sevendigital.yml", :country => "US") \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index a0194b6..bce3236 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,16 +1,19 @@ Nineminutes::Application.routes.draw do - get "sidebar/index" - get "charts/index" - devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" } + devise_for :users, + :controllers => { :omniauth_callbacks => "users/omniauth_callbacks", :registrations => "registrations", :sessions => "sessions" } devise_scope :user do - get '/users/auth/:provider' => 'users/omniauth_callbacks#passthru' + get "/users/auth/:provider" => "users/omniauth_callbacks#passthru" + get "/register" => "devise_auth/registrations#new", :as => :new_user_registration + post "/users" => "devise_auth/registrations#create", :as => :user_registration + get "/login" => "devise_auth/sessions#new", :as => :new_user_session + post "/login" => "devise_auth/sessions#create", :as => :user_session + get "/logout" => "devise_auth/sessions#destroy", :as => :destroy_user_session end get "tracks/index" - get "artists/get_artists", :as => "get_artists" match "/artists/:artist", :to => "artists#show" match "/more_tracks", :to => "artists#more_tracks" match "/more_albums", :to => "artists#more_albums" @@ -23,16 +26,11 @@ Nineminutes::Application.routes.draw do match "/search_video", :to => "tracks#search_video" #resources :artists, :constraints => { :id => /.*/ } - resources :users - resources :sidebar resources :search + resources :users, :only => [ :show ] get "home/", :to => "home#show" - get "charts/", :to => "charts#index" - - # You can have the root of your site routed with "root" - # just remember to delete public/index.html. root :to => "home#index" end diff --git a/lib/last_fm/album.rb b/lib/last_fm/album.rb index 46eb5ca..26e0f1e 100644 --- a/lib/last_fm/album.rb +++ b/lib/last_fm/album.rb @@ -1,6 +1,7 @@ module LastFM class Album < Request + def self.search query, limit = nil, page = nil album_request "search", "albummatches", query, nil, limit, page do |result| result = LastFM::Validator.validate_mash result @@ -11,7 +12,14 @@ module LastFM # return: album name, artist, (top)tags, tracks ( name, duration (in sec) ) mbid (album), release date, image urls ( different sizes ) def self.getInfo album, artist - album_request "getInfo", "album", album, artist + RedisQueryable.look_up_key(:artist, { :hashable => [album, artist] }) do + album_request "getInfo", "album", album, artist do |info| + info = LastFM::Validator.validate_mash info, "tracks" + info = Hashie::Mash.new({ :tracks => [] }) if info.blank? + update_results [current_class_name, __method__], info + RedisQueryable.store :artist, { :hashable => [album, artist] }, info.to_json + end + end end # return: tags ( name, tag´s last.fm-url ) ordered by popularity diff --git a/lib/last_fm/artist.rb b/lib/last_fm/artist.rb index a742ef6..6586af9 100644 --- a/lib/last_fm/artist.rb +++ b/lib/last_fm/artist.rb @@ -12,33 +12,51 @@ module LastFM # return: artist name, tags, similar artists, artist bio (summary / long), mbid, image urls ( different sizes ) def self.getInfo artist - artist_request "getInfo", "artist", artist do |info| - info = LastFM::Validator.validate_mash info, "tag", "image" - update_results [current_class_name, __method__], info + RedisQueryable.look_up_key(:artist, { :hashable => artist, :type => :info }) do + artist_request "getInfo", "artist", artist do |info| + info = LastFM::Validator.validate_mash info, "tag", "image" + update_results [current_class_name, __method__], info + RedisQueryable.store :artist, { :hashable => artist, :type => :info }, info.to_json + end end end - + # return: artists ( name, mbid, image urls ( different sizes ) ) def self.getSimilar artist, limit = nil, page = nil - artist_request "getSimilar", "similarartists", artist, limit + RedisQueryable.look_up_key(:artist, { :hashable => artist, :type => :similar }) do + artist_request "getSimilar", "similarartists", artist, limit do |similar| + similar = LastFM::Validator.validate_mash similar, "tag", "image" + update_results [current_class_name, __method__], similar + RedisQueryable.store :artist, { :hashable => artist, :type => :similar }, similar.to_json + end + end end - + # return: tags ( name, tag´s last.fm-url ) ordered by popularity def self.getTopTags artist artist_request "getTopTags", "toptags", artist end - + # return: tracks ( name, image urls ( different sizes ) ) ordered by popularity def self.getTopTracks artist, limit = nil, page = nil - artist_request "getTopTracks", "toptracks", artist, limit, page + RedisQueryable.look_up_key(:artist, { :hashable => artist, :type => :tracks, :page => page }) do + artist_request "getTopTracks", "toptracks", artist, limit, page do |tracks| + tracks = LastFM::Validator.validate_mash tracks, "tag", "image" + update_results [current_class_name, __method__], tracks + RedisQueryable.store :artist, { :hashable => artist, :type => :tracks, :page => page }, tracks.to_json + end + end end - + # return: albums ( name, mbid, album url, image urls ( different sizes ) ) ordered by popularity def self.getTopAlbums artist, limit = nil, page = nil - artist_request "getTopAlbums", "topalbums", artist, limit, page do |albums| - albums = LastFM::Validator.validate_mash albums, "album" - albums = Hashie::Mash.new({ :album => [] }) if albums.total == "0" - update_results [current_class_name, __method__], albums + RedisQueryable.look_up_key(:artist, { :hashable => artist, :type => :albums, :page => page }) do + artist_request "getTopAlbums", "topalbums", artist, limit, page do |albums| + albums = LastFM::Validator.validate_mash albums, "album" + albums = Hashie::Mash.new({ :album => [] }) if albums.total == "0" + update_results [current_class_name, __method__], albums + RedisQueryable.store :artist, { :hashable => artist, :type => :albums, :page => page }, albums.to_json + end end end diff --git a/lib/last_fm/chart.rb b/lib/last_fm/chart.rb index d4b8b01..2760b9a 100644 --- a/lib/last_fm/chart.rb +++ b/lib/last_fm/chart.rb @@ -2,18 +2,25 @@ module LastFM class Chart < Request def self.getTopArtists limit = nil, page = nil - chart_request "getTopArtists", "artists", limit, page do |artists| - LastFM::Validator.validate_mash artists, "image" - update_results [current_class_name, __method__], artists + RedisQueryable.look_up_key(:chart, { :type => :artists, :page => page }) do + chart_request "getTopArtists", "artists", limit, page do |artists| + artists = LastFM::Validator.validate_mash artists, "image" + update_results [current_class_name, __method__], artists + RedisQueryable.store :chart, { :type => :artists, :page => page }, artists.to_json + end end end def self.getTopTracks limit = nil, page = nil - chart_request "getTopTracks", "tracks", limit, page do |tracks| - LastFM::Validator.validate_mash tracks - update_results [current_class_name, __method__], tracks + RedisQueryable.look_up_key(:chart, { :type => :tracks, :page => page }) do + chart_request "getTopTracks", "tracks", limit, page do |tracks| + tracks = LastFM::Validator.validate_mash tracks + update_results [current_class_name, __method__], tracks + RedisQueryable.store :chart, { :type => :tracks, :page => page }, tracks.to_json + end end end + end end \ No newline at end of file diff --git a/lib/redis_queryable.rb b/lib/redis_queryable.rb new file mode 100644 index 0000000..f5cec55 --- /dev/null +++ b/lib/redis_queryable.rb @@ -0,0 +1,53 @@ +module RedisQueryable + + VALID_NAMESPACES = [ :artist, :album, :chart ] + EXPIRATION = { + :artist => { :tracks => 3, :albums => 7, :similar => 14, :info => 7 }, + :chart => { :tracks => 10, :artists => 10 }, + :album => 28 + } + + def self.store namespace, key_hash, value + key = build_key key_hash.values + redis = switch_to_namespace namespace + + expires = key_hash.has_key?(:type) ? EXPIRATION[namespace][key_hash[:type]] : EXPIRATION[namespace] + redis.setex key, expires.to_i.days, value + end + + def self.get namespace, key_hash + key = build_key key_hash.values + redis = switch_to_namespace namespace + json = redis.get key + Hashie::Mash.new(JSON.parse(json)) + end + + def self.look_up_key namespace, key_hash, &block + if exists_key? namespace, key_hash + get namespace, key_hash + else + block.call + end + end + + + private + + def self.exists_key? namespace, key_hash + key = build_key key_hash.values + redis = switch_to_namespace namespace + redis.exists key + end + + def self.build_key key_array + key_array.flatten.map do |value| + value.is_a?(String) ? Digest::SHA1.hexdigest(value) : value.to_s + end.join(":") + end + + def self.switch_to_namespace namespace + return Redis::Namespace.new(namespace, :redis => $redis) if VALID_NAMESPACES.include? namespace + $redis + end + +end \ No newline at end of file diff --git a/public/javascripts/ajax/routes.js b/public/javascripts/ajax/routes.js index 637f179..c5483fc 100644 --- a/public/javascripts/ajax/routes.js +++ b/public/javascripts/ajax/routes.js @@ -23,4 +23,28 @@ $(document).ready(function(){ show_flash(false); load_site_request(search_path, this.params['q']); }); + + // Sign Up Page + Path.map(hashbang+register_path).to(function(){ + show_flash(false); + load_site_request(register_path, ""); + }); + + // Sign In Page + Path.map(hashbang+login_path).to(function(){ + show_flash(false); + load_site_request(login_path, ""); + }); + + // Sign Out Page + Path.map(hashbang+logout_path).to(function(){ + show_flash(false); + load_site_request(logout_path, ""); + }); + + // User Show Page + Path.map(hashbang+user_path+":user").to(function(){ + show_flash(false); + load_site_request(user_path, this.params['user']); + }); }); \ No newline at end of file diff --git a/public/javascripts/config.js b/public/javascripts/config.js index c575a2d..4f915bf 100644 --- a/public/javascripts/config.js +++ b/public/javascripts/config.js @@ -7,6 +7,10 @@ const home_path = "/home"; const charts_path = "/charts"; const search_path = "/search/"; const search_autocomplete_path = "/autocomplete/"; +const user_path = "/users/"; +const register_path = "/register"; +const login_path = "/login"; +const logout_path = "/logout"; $(document).ready(function(){ Path.root(hashbang+home_path); diff --git a/public/javascripts/layout.js b/public/javascripts/layout.js index ccdc6b5..0f65447 100644 --- a/public/javascripts/layout.js +++ b/public/javascripts/layout.js @@ -152,7 +152,8 @@ function init_site(link){ init_autocomplete(); set_active_navigation(charts_path); break; - + case user_path: + init_tabs(); } } diff --git a/public/stylesheets/9minutes.css b/public/stylesheets/9minutes.css index efd3de5..b273067 100644 --- a/public/stylesheets/9minutes.css +++ b/public/stylesheets/9minutes.css @@ -1 +1 @@ -body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td{margin:0;padding:0}table{border-collapse:collapse;border-spacing:0}fieldset,img{border:0}address,caption,cite,code,dfn,em,strong,th,var,optgroup{font-style:inherit;font-weight:inherit}del,ins{text-decoration:none}li{list-style:none}caption,th{text-align:left}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal}q:before,q:after{content:''}abbr,acronym{border:0;font-variant:normal}sup{vertical-align:baseline}sub{vertical-align:baseline}legend{color:#000}input,button,textarea,select,optgroup,option{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit}input,button,textarea,select{*font-size:100%}.clean{clear:both}b,strong{font-family:"Segoe UI", Corbel, Arial, sans-serif}a{cursor:pointer}body{background:#05070a url("/images/backgrounds/overall.png") no-repeat center top;color:#15191d;font-size:12px;font-family:"Segoe UI", Corbel, Arial, sans-serif}#bg_stripe{height:228px;width:100%;position:absolute;top:136px;background:transparent url("/images/backgrounds/stripe.png") repeat}#site{width:950px;position:relative;margin:0 auto}#head{height:115px}#head h1{margin:36px 0 0 94px;float:left}#navigation{float:right;overflow:hidden}#navigation li{float:left}#navigation li.active{background:url("/images/backgrounds/navi-hover.png")}#navigation li.search{width:200px;font-size:16px;color:#ffffff;line-height:58px;display:inline-block;background:transparent url("/images/backgrounds/stripe.png") repeat;margin-top:21px;height:58px;padding-left:20px;margin-left:20px}#navigation li.search img{vertical-align:middle;margin-left:10px}#navigation li.search .text{width:150px;height:45px;border:0;background:0;color:#fff}#navigation li.search .submit{display:none}#navigation li > a{font-size:16px;font-weight:bold;color:#ffffff;height:79px;line-height:99px;width:141px;display:inline-block;text-decoration:none;text-align:center}#foot{clear:both;padding:25px 0;float:right}#foot h6{color:#243037;font-size:11px;float:left;height:20px;line-height:22px}#foot ul{float:left;height:20px;line-height:20px}#foot li{float:left;margin-left:33px}#foot a{color:#ffffff;text-transform:uppercase;text-decoration:none;font-size:11px;background:url("/images/icons/arrow-foot.png") left 3px no-repeat;padding-left:22px;display:inline-block;height:20px;line-height:20px}.tabs_js .nav li{cursor:pointer}.tabs{float:right}.tabs .content{background:#fff;padding:48px 37px}.tabs .content > div{display:none;position:relative}.tabs .more{background:#f4f6f9;border-top:1px solid #e5e9ef;height:40px;display:block;text-align:center;line-height:40px;font-weight:bold}.tabs .more.disabled{opacity:0.3;cursor:default}.tabs.w01 .nav{width:564px}.tabs.w01 .content{width:490px}.tabs.w01 .content > div{width:490px}.tabs.w01 .content .more{width:564px;margin:7px -37px -48px -37px}.tabs.w02 .nav{width:750px}.tabs.w02 .content{width:676px}.tabs.w02 .content > div{width:676px}.tabs.w02 .content .more{width:750px;margin:7px -37px -48px -37px}.tabs.w03 .nav{width:950px}.tabs.w03 .content{width:876px}.tabs.w03 .content > div{width:876px}.tabs.w03 .content .more{width:950px;margin:7px -37px -48px -37px}.tabs .nav{color:#fff;overflow:hidden;background:transparent url("/images/backgrounds/stripe-dark.png") repeat}.tabs .nav li{width:120px;height:54px;line-height:54px;float:left;text-align:center;text-transform:lowercase;font-size:15px}.tabs .nav li.active{background:#fff;color:#2f3a40}#content .information{overflow:hidden;padding-bottom:22px;background:transparent url("/images/backgrounds/stripe.png") repeat}#content .information .content > div{display:none}#content .information .nav{margin-left:22px;float:left}#content .information .nav li{width:37px;height:25px;margin-bottom:13px}#content .information .nav li.active{background:url("/images/icons/artist-information-active-arrow.png") no-repeat right 10px;cursor:default}#content .information .content{float:right;width:280px;margin-right:22px;color:#fff}#loading,#error{position:fixed;top:0;left:0;width:100%;height:30px;line-height:30px;background:#0086cc;color:#fff;text-align:center;font-weight:bold;text-transform:uppercase;display:none;z-index:999}#error{background:#ee0000}#white{width:870px;padding:50px 40px;background:#fff}#block{width:100%;height:100%;position:fixed;z-index:22;background:#000;opacity:0;display:none}.box{padding:10px;border:1px solid #e5e7e9;background:#f4f6f9}#artist_left{float:left;width:386px}#artist_left h1{width:386px}#artist_left .information{width:386px}#artist_left #slider{position:relative;width:386px;height:240px;overflow:hidden;background:url("/images/placeholder/artist-big.png") no-repeat 0 0}#artist_left #slider img{position:absolute;top:0;left:0;max-width:386px}#artist_left h1{color:#fff;font-size:30px;overflow:hidden;height:74px;line-height:70px;text-indent:28px;margin-bottom:23px;background:transparent url("/images/backgrounds/stripe.png") repeat}#artist_left #artist_links ul{margin:-2px 0 30px 0}#artist_left #artist_links li{margin-bottom:12px;font-family:"Segoe UI", Corbel, Arial, sans-serif;overflow:hidden}#artist_left #artist_links li a{text-decoration:none;font-size:10px;color:#fff}#artist_left #artist_links li a:hover h3{color:#00a7ff}#artist_left #artist_links li h3{color:#0086cc;font-size:13px;font-weight:normal}#artist_left #artist_tags li{background:url("/images/icons/tag.png") no-repeat left 2px;color:#fff;padding-left:20px;margin-bottom:12px;font-family:"Segoe UI", Corbel, Arial, sans-serif}#artist_left #artist_info{font-family:"Segoe UI", Corbel, Arial, sans-serif;font-size:11px;line-height:16px}#artist_left h2{font-size:18px;color:#0086cc;font-weight:normal;margin:-2px 0 10px 0}#artist_left .heart{float:right;width:22px;height:19px;display:inline-block;margin:28px 20px 0 0;background:url("/images/icons/heart.png") no-repeat 0 0}#top_artist{position:relative;width:500px;height:270px;background:url("/images/icons/loading.gif") no-repeat 50% 50%;overflow:hidden}#top_artist img{position:absolute;top:0;right:0;display:none;max-width:500px;max-height:270px;overflow:hidden}#top_artist .nivo-controlNav{position:absolute;bottom:-70px}#top_artist .nivo-controlNav img{display:inline;position:relative;margin-right:10px}#user_left{float:left;width:200px}#user_left h1{width:200px}#user_left .information{width:200px}#user_left .picture{float:left;position:relative;width:200px;height:200px}#user_left h1{font-size:18px;line-height:44px;height:44px}#user_left .nav li{background:url("/images/icons/artist-information-active-arrow.png") no-repeat right 10px;cursor:default}#user_left .nav li:last-child{margin-bottom:0}#user_left .con{margin-left:80px}#user_left .con li{height:25px;margin-bottom:13px;color:White;line-height:25px}#user_left .con li:last-child{margin-bottom:0}#charts{width:530px;float:left}#charts li{overflow:hidden;display:block;padding-bottom:10px;border-bottom:1px solid #f0f2f4;margin-bottom:10px}#charts li h6{font-size:28px;font-weight:bold;float:left;height:50px;color:#a3adb5;line-height:50px;margin-left:15px;width:50px}#charts li .img{width:90px;height:50px;background:url("/images/placeholder/artist.png") no-repeat 0 0;float:left;overflow:hidden;position:relative}#charts li .img img{max-width:90px}#charts li .text{float:left;margin-left:15px}#charts li .text h2{margin:-3px 0 5px 0}#charts li .text h2 a{color:#0086cc;font-size:16px;text-decoration:none}#charts li .text h2 a:hover{text-decoration:underline}#search_bar{width:500px;float:left;border:0;margin-bottom:20px;position:relative;padding:15px}#search_bar input{width:498px;height:35px;text-indent:10px;font-size:14px;border:1px solid #dadce0;border-radius:4px;-moz-border-radius:4px;-webkit-border-radius:4px}#search_bar input:focus{border-color:#0086cc}#search_bar .button{position:absolute;width:20px;height:20px;right:26px;top:24px}#album_box{position:absolute;top:69px;left:100px;display:none;z-index:12;border:7px solid rgba(255, 255, 255, 0.8);-moz-box-shadow:0 0 2px 2px rgba(31, 34, 40, 0.1);-webkit-box-shadow:0 0 2px 2px rgba(31, 34, 40, 0.1);box-shadow:0 0 2px 2px rgba(31, 34, 40, 0.1)}#album_box > span{position:absolute;top:-19px;left:70px;background:url("/images/icons/arrow.png") no-repeat;width:47px;height:23px}#album_box .headline{background:#e3e6ec;float:left;width:128px;height:180px;padding:10px;border-right:1px solid #d6dce4}#album_box .headline h4{font-size:18px;line-height:16px}#album_box .headline h4 span{font-size:14px;color:#0086cc}#album_box .headline img{margin-bottom:10px;width:128px;height:128px}#album_box .wrap{background:#f4f6f9;float:right;max-height:200px;overflow:auto;width:279px}#album_box .wrap li{padding:7px 9px;overflow:hidden;width:259px;border-bottom:1px solid #e0e6ee;border-top:1px solid #f7f9fb}#album_box .wrap li span{color:#9aa7b3;width:20px;display:inline-block}#album_box .wrap li .playsong,#album_box .wrap li .add{width:20px;height:20px;display:inline-block;background:url("/images/icons/list-controls.png") no-repeat 0 0;vertical-align:middle;float:right}#album_box .wrap li .add{margin-right:6px;background-position:0 -20px}.player{float:right;height:47px;margin:52px 17px 0 0;line-height:47px}.player a{float:left}.player .play{margin:-8px 5px 0 5px}.player .forward,.player .backward{display:inline-block;width:32px;height:32px}.player .volume,.player .repeat,.player #full{margin:-5px 0 0 20px}#sidebar{float:right;width:320px}#sidebar .advertisment{width:300px;height:270px}#sidebar img{float:left}#sidebar sup{display:block;height:20px;line-height:20px;float:left}.nivoSlider{position:relative}.nivoSlider img{position:absolute;top:0px;left:0px}.nivo-slice{display:block;position:absolute;z-index:5;height:100%}.nivo-box{display:block;position:absolute;z-index:5}.jspContainer{overflow:hidden;position:relative}.jspPane{position:absolute}.jspVerticalBar{position:absolute;top:0;right:0;width:6px;height:100%}.jspHorizontalBar{width:0;height:0;display:none}.jspVerticalBar *,.jspHorizontalBar *{margin:0;padding:0}.jspCap{display:none}.jspHorizontalBar .jspCap{float:left}.jspTrack{background:transparent;position:relative;padding:0 0}.jspDrag{background:#e0e6ee;position:relative;top:0;left:2px;width:4px;cursor:pointer}.jspHorizontalBar .jspTrack,.jspHorizontalBar .jspDrag{float:left;height:100%}.jspArrow{background:#50506d;text-indent:-20000px;display:block;cursor:pointer}.jspArrow.jspDisabled{cursor:default;background:#80808d}.jspVerticalBar .jspArrow{height:16px}.jspHorizontalBar .jspArrow{width:16px;float:left;height:100%}.jspVerticalBar .jspArrow:focus{outline:none}.jspCorner{background:#eeeef4;float:left;height:100%}* html .jspCorner{margin:0 -3px 0 0}.list{margin-bottom:20px;display:block;float:left}.list.songs li{height:24px;line-height:24px;width:100%;font-size:13px;margin-bottom:12px;font-family:"Segoe UI", Corbel, Arial, sans-serif}.list.songs li span{color:#a3adb5}.list.songs li a{color:#a3adb5;text-decoration:none}.list.songs li a:hover{color:#0086cc}.list.songs li:last-child{margin-bottom:0}.list.songs li .playsong,.list.songs li .add{width:20px;height:20px;display:inline-block;margin-right:6px;background:url("/images/icons/list-controls.png") no-repeat 0 0;vertical-align:middle}.list.songs li .add{margin-right:16px;background-position:0 -20px}.list.albums{margin-bottom:10px}.list.albums > li{margin-bottom:15px;min-width:450px;position:relative;clear:both}.list.albums > li:last-child{margin-bottom:0}.list.albums > li .songsbtn{text-transform:uppercase;text-decoration:none;color:#0086cc;background:url("/images/icons/list-controls.png") no-repeat 0 -60px;height:20px;line-height:20px;text-indent:25px;display:inline-block;margin-top:10px;font-size:11px}.list.albums .img{margin-right:10px;position:relative;float:left;overflow:hidden;background:url("/images/backgrounds/album.png") 0 6px no-repeat;width:90px;height:74px}.list.albums .img .cover{width:64px;height:64px;margin-left:18px}.list.albums .img .playall{position:absolute;top:0;left:18px;background:transparent url("/images/backgrounds/stripe.png") repeat;width:64px;height:64px;display:none}.list.albums .img .playall a{display:inline-block;width:20px;height:20px;background:url("/images/icons/list-controls.png") no-repeat 0 -40px;margin:22px 0 0 22px}.list.albums .name{font-size:16px;line-height:17px;margin-top:-2px}.list.albums .artist{font-size:12px;color:#a3adb5}.list.related li{overflow:hidden;float:left;margin:0 20px 20px 0;width:150px}.list.related li a{text-decoration:none}.list.related li h5{font-size:14px;text-decoration:none!important;color:#2f3a40;height:30px;line-height:30px;border-bottom:2px solid #0086cc}.list.related li h5 span{color:#0086cc;font-size:11px}.list.related li h5 span:before{content:"("}.list.related li h5 span:after{content:"%)"}.list.related li div{width:150px;height:95px;float:left;overflow:hidden;position:relative;background:url("/images/placeholder/related.png") no-repeat 0 0}.list.artists{width:530px;float:left}.list.artists li{overflow:hidden;display:block;padding-bottom:10px;border-bottom:1px solid #f0f2f4;margin-bottom:10px}.list.artists li .img{width:90px;height:50px;float:left;overflow:hidden;position:relative;background:url("/images/placeholder/artist.png") no-repeat 0 0}.list.artists li .img img{max-width:90px}.list.artists li .text{float:left;margin-left:15px}.list.artists li .text h2{margin:-3px 0 5px 0}.list.artists li .text h2 a{color:#0086cc;font-size:16px;text-decoration:none}.list.artists li .text h2 a:hover{text-decoration:underline}.playlist{background:#080a0c;width:150px;display:none;position:absolute;left:0;top:0}#fullscreen_wrap{width:100%;height:100%;position:fixed;z-index:70;background:#000;top:0;left:0;display:none}#fullscreen{width:950px;position:absolute;margin-left:-475px;z-index:70;opacity:0;top:0;left:50%;display:none}#fullscreen h2{font-size:18px;color:#fff;text-transform:uppercase;font-weight:bold;line-height:14px}#fullscreen h1{font-size:28px;color:#fff;margin-bottom:20px}#fullscreen #video{float:left;width:640px;height:360px;background:transparent url("/images/backgrounds/stripe.png") repeat}#fullscreen .sidebar{float:right;width:310px;height:360px;background:transparent url("/images/backgrounds/stripe.png") repeat}#fullscreen .sidebar .top{width:310px;height:125px;background:transparent url("/images/backgrounds/stripe.png") repeat;text-align:center;line-height:125px}#fullscreen .sidebar .top .player{float:left;margin-top:47px;margin-left:40px}#fullscreen .sidebar .play_list{width:310px;height:235px;padding:10px 0;overflow:auto}#fullscreen .sidebar .play_list li{padding:6px 25px}#fullscreen .sidebar .play_list li h3{font-size:22px;color:white;line-height:22px}#fullscreen .sidebar .play_list li h3 span{display:block;font-size:12px;text-transform:uppercase;color:#0086cc}#fullscreen .sidebar .play_list .jspVerticalBar{left:0!important;opacity:0.02}.ac_results{padding:0px;border:1px solid black;background-color:white;overflow:hidden;z-index:99999}.ac_results ul{width:100%;list-style-position:outside;list-style:none;padding:0;margin:0}.ac_results li{margin:0px;padding:2px 5px;cursor:default;display:block;font:menu;font-size:12px;line-height:16px;overflow:hidden}.ac_loading{background:white url("indicator.gif") right center no-repeat}.ac_odd{background-color:#eee}.ac_over{background-color:#0A246A;color:white} +body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td{margin:0;padding:0}table{border-collapse:collapse;border-spacing:0}fieldset,img{border:0}address,caption,cite,code,dfn,em,strong,th,var,optgroup{font-style:inherit;font-weight:inherit}del,ins{text-decoration:none}li{list-style:none}caption,th{text-align:left}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal}q:before,q:after{content:''}abbr,acronym{border:0;font-variant:normal}sup{vertical-align:baseline}sub{vertical-align:baseline}legend{color:#000}input,button,textarea,select,optgroup,option{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit}input,button,textarea,select{*font-size:100%}.clean{clear:both}b,strong{font-family:"Segoe UI", Corbel, Arial, sans-serif}a{cursor:pointer}body{background:#05070a url("/images/backgrounds/overall.png") no-repeat center top;color:#15191d;font-size:12px;font-family:"Segoe UI", Corbel, Arial, sans-serif}#bg_stripe{height:228px;width:100%;position:absolute;top:136px;background:transparent url("/images/backgrounds/stripe.png") repeat}#site{width:950px;position:relative;margin:0 auto}#head{height:115px}#head h1{margin:36px 0 0 94px;float:left}#navigation{float:right;overflow:hidden}#navigation li{float:left}#navigation li.active{background:url("/images/backgrounds/navi-hover.png")}#navigation li.search{width:200px;font-size:16px;color:#ffffff;line-height:58px;display:inline-block;background:transparent url("/images/backgrounds/stripe.png") repeat;margin-top:21px;height:58px;padding-left:20px;margin-left:20px}#navigation li.search img{vertical-align:middle;margin-left:10px}#navigation li.search .text{width:150px;height:45px;border:0;background:0;color:#fff}#navigation li.search .submit{display:none}#navigation li > a{font-size:16px;font-weight:bold;color:#ffffff;height:79px;line-height:99px;width:141px;display:inline-block;text-decoration:none;text-align:center}#foot{clear:both;padding:25px 0;float:right}#foot h6{color:#243037;font-size:11px;float:left;height:20px;line-height:22px}#foot ul{float:left;height:20px;line-height:20px}#foot li{float:left;margin-left:33px}#foot a{color:#ffffff;text-transform:uppercase;text-decoration:none;font-size:11px;background:url("/images/icons/arrow-foot.png") left 3px no-repeat;padding-left:22px;display:inline-block;height:20px;line-height:20px}.tabs_js .nav li{cursor:pointer}.tabs{float:right}.tabs .content{background:#fff;padding:48px 37px}.tabs .content > div{display:none;position:relative}.tabs .more{background:#f4f6f9;border-top:1px solid #e5e9ef;height:40px;display:block;text-align:center;line-height:40px;font-weight:bold}.tabs .more.disabled{opacity:0.3;cursor:default}.tabs.w01 .nav{width:564px}.tabs.w01 .content{width:490px}.tabs.w01 .content > div{width:490px}.tabs.w01 .content .more{width:564px;margin:7px -37px -48px -37px}.tabs.w02 .nav{width:750px}.tabs.w02 .content{width:676px}.tabs.w02 .content > div{width:676px}.tabs.w02 .content .more{width:750px;margin:7px -37px -48px -37px}.tabs.w03 .nav{width:950px}.tabs.w03 .content{width:876px}.tabs.w03 .content > div{width:876px}.tabs.w03 .content .more{width:950px;margin:7px -37px -48px -37px}.tabs .nav{color:#fff;overflow:hidden;background:transparent url("/images/backgrounds/stripe-dark.png") repeat}.tabs .nav li{width:120px;height:54px;line-height:54px;float:left;text-align:center;text-transform:lowercase;font-size:15px}.tabs .nav li.active{background:#fff;color:#2f3a40}#content .information{overflow:hidden;padding-bottom:22px;background:transparent url("/images/backgrounds/stripe.png") repeat}#content .information .content > div{display:none}#content .information .nav{margin-left:22px;float:left}#content .information .nav li{width:37px;height:25px;margin-bottom:13px}#content .information .nav li.active{background:url("/images/icons/artist-information-active-arrow.png") no-repeat right 10px;cursor:default}#content .information .content{float:right;width:280px;margin-right:22px;color:#fff}#loading,#error{position:fixed;top:0;left:0;width:100%;height:30px;line-height:30px;background:#0086cc;color:#fff;text-align:center;font-weight:bold;text-transform:uppercase;display:none;z-index:999}#error{background:#ee0000}#white{width:870px;padding:50px 40px;background:#fff}#block{width:100%;height:100%;position:fixed;z-index:22;background:#000;opacity:0;display:none}.box{padding:10px;border:1px solid #e5e7e9;background:#f4f6f9}#artist_left{float:left;width:386px}#artist_left h1{width:386px}#artist_left .information{width:386px}#artist_left #slider{position:relative;width:386px;height:240px;overflow:hidden;background:url("/images/placeholder/artist-big.png") no-repeat 0 0}#artist_left #slider img{position:absolute;top:0;left:0;max-width:386px}#artist_left h1{color:#fff;font-size:30px;overflow:hidden;height:74px;line-height:70px;text-indent:28px;margin-bottom:23px;background:transparent url("/images/backgrounds/stripe.png") repeat}#artist_left #artist_links ul{margin:-2px 0 30px 0}#artist_left #artist_links li{margin-bottom:12px;font-family:"Segoe UI", Corbel, Arial, sans-serif;overflow:hidden}#artist_left #artist_links li a{text-decoration:none;font-size:10px;color:#fff}#artist_left #artist_links li a:hover h3{color:#00a7ff}#artist_left #artist_links li h3{color:#0086cc;font-size:13px;font-weight:normal}#artist_left #artist_tags li{background:url("/images/icons/tag.png") no-repeat left 2px;color:#fff;padding-left:20px;margin-bottom:12px;font-family:"Segoe UI", Corbel, Arial, sans-serif}#artist_left #artist_info{font-family:"Segoe UI", Corbel, Arial, sans-serif;font-size:11px;line-height:16px}#artist_left h2{font-size:18px;color:#0086cc;font-weight:normal;margin:-2px 0 10px 0}#artist_left .heart{float:right;width:22px;height:19px;display:inline-block;margin:28px 20px 0 0;background:url("/images/icons/heart.png") no-repeat 0 0}#top_artist{position:relative;width:500px;height:270px;background:url("/images/icons/loading.gif") no-repeat 50% 50%;overflow:hidden}#top_artist img{position:absolute;top:0;right:0;display:none;max-width:500px;max-height:270px;overflow:hidden}#top_artist .nivo-controlNav{position:absolute;bottom:-70px}#top_artist .nivo-controlNav img{display:inline;position:relative;margin-right:10px}#user_left{float:left;width:200px}#user_left h1{width:200px}#user_left .information{width:200px}#user_left .picture{float:left;position:relative;width:200px;height:200px}#user_left h1{font-size:18px;line-height:44px;height:44px}#user_left .nav li{background:url("/images/icons/artist-information-active-arrow.png") no-repeat right 10px;cursor:default}#user_left .nav li:last-child{margin-bottom:0}#user_left .con{margin-left:80px}#user_left .con li{height:25px;margin-bottom:13px;color:White;line-height:25px}#user_left .con li:last-child{margin-bottom:0}#charts{width:530px;float:left}#charts li{overflow:hidden;display:block;padding-bottom:10px;border-bottom:1px solid #f0f2f4;margin-bottom:10px}#charts li h6{font-size:28px;font-weight:bold;float:left;height:50px;color:#a3adb5;line-height:50px;margin-left:15px;width:50px}#charts li .img{width:90px;height:50px;background:url("/images/placeholder/artist.png") no-repeat 0 0;float:left;overflow:hidden;position:relative}#charts li .img img{max-width:90px}#charts li .text{float:left;margin-left:15px}#charts li .text h2{margin:-3px 0 5px 0}#charts li .text h2 a{color:#0086cc;font-size:16px;text-decoration:none}#charts li .text h2 a:hover{text-decoration:underline}#search_bar{width:500px;float:left;border:0;margin-bottom:20px;position:relative;padding:15px}#search_bar input{width:498px;height:35px;text-indent:10px;font-size:14px;border:1px solid #dadce0;border-radius:4px;-moz-border-radius:4px;-webkit-border-radius:4px}#search_bar input:focus{border-color:#0086cc}#search_bar .button{position:absolute;width:20px;height:20px;right:26px;top:24px}#album_box{position:absolute;top:69px;left:100px;display:none;z-index:12;border:7px solid rgba(255, 255, 255, 0.8);-moz-box-shadow:0 0 2px 2px rgba(31, 34, 40, 0.1);-webkit-box-shadow:0 0 2px 2px rgba(31, 34, 40, 0.1);box-shadow:0 0 2px 2px rgba(31, 34, 40, 0.1)}#album_box > span{position:absolute;top:-19px;left:70px;background:url("/images/icons/arrow.png") no-repeat;width:47px;height:23px}#album_box .headline{background:#e3e6ec;float:left;width:128px;height:180px;padding:10px;border-right:1px solid #d6dce4}#album_box .headline h4{font-size:18px;line-height:16px}#album_box .headline h4 span{font-size:14px;color:#0086cc}#album_box .headline img{margin-bottom:10px;width:128px;height:128px}#album_box .wrap{background:#f4f6f9;float:right;max-height:200px;overflow:auto;width:279px}#album_box .wrap li{padding:7px 9px;overflow:hidden;width:259px;border-bottom:1px solid #e0e6ee;border-top:1px solid #f7f9fb}#album_box .wrap li span{color:#9aa7b3;width:20px;display:inline-block}#album_box .wrap li .playsong,#album_box .wrap li .add{width:20px;height:20px;display:inline-block;background:url("/images/icons/list-controls.png") no-repeat 0 0;vertical-align:middle;float:right}#album_box .wrap li .add{margin-right:6px;background-position:0 -20px}.player{float:right;height:47px;margin:52px 17px 0 0;line-height:47px}.player a{float:left}.player .play{margin:-8px 5px 0 5px}.player .forward,.player .backward{display:inline-block;width:32px;height:32px}.player .volume,.player .repeat,.player #full{margin:-5px 0 0 20px}#sidebar{float:right;width:320px}#sidebar .advertisment{width:300px;height:270px}#sidebar img{float:left}#sidebar sup{display:block;height:20px;line-height:20px;float:left}.nivoSlider{position:relative}.nivoSlider img{position:absolute;top:0px;left:0px}.nivo-slice{display:block;position:absolute;z-index:5;height:100%}.nivo-box{display:block;position:absolute;z-index:5}.jspContainer{overflow:hidden;position:relative}.jspPane{position:absolute}.jspVerticalBar{position:absolute;top:0;right:0;width:6px;height:100%}.jspHorizontalBar{width:0;height:0;display:none}.jspVerticalBar *,.jspHorizontalBar *{margin:0;padding:0}.jspCap{display:none}.jspHorizontalBar .jspCap{float:left}.jspTrack{background:transparent;position:relative;padding:0 0}.jspDrag{background:#e0e6ee;position:relative;top:0;left:2px;width:4px;cursor:pointer}.jspHorizontalBar .jspTrack,.jspHorizontalBar .jspDrag{float:left;height:100%}.jspArrow{background:#50506d;text-indent:-20000px;display:block;cursor:pointer}.jspArrow.jspDisabled{cursor:default;background:#80808d}.jspVerticalBar .jspArrow{height:16px}.jspHorizontalBar .jspArrow{width:16px;float:left;height:100%}.jspVerticalBar .jspArrow:focus{outline:none}.jspCorner{background:#eeeef4;float:left;height:100%}* html .jspCorner{margin:0 -3px 0 0}.list{margin-bottom:20px;display:block;float:left}.list.songs li{height:24px;line-height:24px;width:100%;font-size:13px;margin-bottom:12px;font-family:"Segoe UI", Corbel, Arial, sans-serif}.list.songs li span{color:#a3adb5}.list.songs li a{color:#a3adb5;text-decoration:none}.list.songs li a:hover{color:#0086cc}.list.songs li:last-child{margin-bottom:0}.list.songs li .playsong,.list.songs li .add{width:20px;height:20px;display:inline-block;margin-right:6px;background:url("/images/icons/list-controls.png") no-repeat 0 0;vertical-align:middle}.list.songs li .add{margin-right:16px;background-position:0 -20px}.list.albums{margin-bottom:10px}.list.albums > li{margin-bottom:15px;min-width:450px;position:relative;clear:both}.list.albums > li:last-child{margin-bottom:0}.list.albums > li .songsbtn{text-transform:uppercase;text-decoration:none;color:#0086cc;background:url("/images/icons/list-controls.png") no-repeat 0 -60px;height:20px;line-height:20px;text-indent:25px;display:inline-block;margin-top:10px;font-size:11px}.list.albums .img{margin-right:10px;position:relative;float:left;overflow:hidden;background:url("/images/backgrounds/album.png") 0 6px no-repeat;width:90px;height:74px}.list.albums .img .cover{width:64px;height:64px;margin-left:18px}.list.albums .img .playall{position:absolute;top:0;left:18px;background:transparent url("/images/backgrounds/stripe.png") repeat;width:64px;height:64px;display:none}.list.albums .img .playall a{display:inline-block;width:20px;height:20px;background:url("/images/icons/list-controls.png") no-repeat 0 -40px;margin:22px 0 0 22px}.list.albums .name{font-size:16px;line-height:17px;margin-top:-2px}.list.albums .artist{font-size:12px;color:#a3adb5}.list.related li{overflow:hidden;float:left;margin:0 20px 20px 0;width:150px}.list.related li a{text-decoration:none}.list.related li h5{font-size:14px;text-decoration:none!important;color:#2f3a40;height:30px;line-height:30px;border-bottom:2px solid #0086cc}.list.related li h5 span{color:#0086cc;font-size:11px}.list.related li h5 span:before{content:"("}.list.related li h5 span:after{content:"%)"}.list.related li div{width:150px;height:95px;float:left;overflow:hidden;position:relative;background:url("/images/placeholder/related.png") no-repeat 0 0}.list.artists{width:530px;float:left}.list.artists li{overflow:hidden;display:block;padding-bottom:10px;border-bottom:1px solid #f0f2f4;margin-bottom:10px}.list.artists li .img{width:90px;height:50px;float:left;overflow:hidden;position:relative;background:url("/images/placeholder/artist.png") no-repeat 0 0}.list.artists li .img img{max-width:90px}.list.artists li .text{float:left;margin-left:15px}.list.artists li .text h2{margin:-3px 0 5px 0}.list.artists li .text h2 a{color:#0086cc;font-size:16px;text-decoration:none}.list.artists li .text h2 a:hover{text-decoration:underline}.playlist{background:#080a0c;width:150px;display:none;position:absolute;left:0;top:0}#fullscreen_wrap{width:100%;height:100%;position:fixed;z-index:70;background:#000;top:0;left:0;display:none}#fullscreen{width:950px;position:absolute;margin-left:-475px;z-index:70;opacity:0;top:0;left:50%;display:none}#fullscreen h2{font-size:18px;color:#fff;text-transform:uppercase;font-weight:bold;line-height:14px}#fullscreen h1{font-size:28px;color:#fff;margin-bottom:20px}#fullscreen #video{float:left;width:640px;height:360px;background:transparent url("/images/backgrounds/stripe.png") repeat}#fullscreen .sidebar{float:right;width:310px;height:360px;background:transparent url("/images/backgrounds/stripe.png") repeat}#fullscreen .sidebar .top{width:310px;height:125px;background:transparent url("/images/backgrounds/stripe.png") repeat;text-align:center;line-height:125px}#fullscreen .sidebar .top .player{float:left;margin-top:47px;margin-left:40px}#fullscreen .sidebar .play_list{width:310px;height:235px;padding:10px 0;overflow:auto}#fullscreen .sidebar .play_list li{padding:6px 25px}#fullscreen .sidebar .play_list li h3{font-size:22px;color:white;line-height:22px}#fullscreen .sidebar .play_list li h3 span{display:block;font-size:12px;text-transform:uppercase;color:#0086cc}#fullscreen .sidebar .play_list .jspVerticalBar{left:0!important;opacity:0.02}.ac_results{padding:0px;border:1px solid black;background-color:white;overflow:hidden;z-index:99999}.ac_results ul{width:100%;list-style-position:outside;list-style:none;padding:0;margin:0}.ac_results li{margin:0px;padding:2px 5px;cursor:default;display:block;font:menu;font-size:12px;line-height:16px;overflow:hidden}.ac_loading{background:white url("indicator.gif") right center no-repeat}.ac_odd{background-color:#eee}.ac_over{background-color:#0A246A;color:white} \ No newline at end of file