From eb8b14f3ddaff7524f1a9acddc8d36c84d43e4e3 Mon Sep 17 00:00:00 2001 From: Guillaume Dott Date: Wed, 21 Oct 2015 12:37:28 +0200 Subject: [PATCH] Add basic features * list movies * search movies * add and remove movies from the list --- .gitignore | 12 ++----- lib/librarix.rb | 14 ++++++-- lib/librarix/application.rb | 42 ++++++++++++++++++++++++ lib/librarix/assets/application.scss | 35 ++++++++++++++++++++ lib/librarix/public/application.css | 1 + lib/librarix/public/application.js | 2 ++ lib/librarix/redis.rb | 49 ++++++++++++++++++++++++++++ lib/librarix/redis/movie.rb | 44 +++++++++++++++++++++++++ lib/librarix/the_movie_db.rb | 33 +++++++++++++++++++ lib/librarix/views/application.js | 0 lib/librarix/views/index.slim | 6 ++++ lib/librarix/views/layout.slim | 11 +++++++ lib/librarix/views/movie.slim | 16 +++++++++ lib/librarix/views/search.slim | 10 ++++++ librarix.gemspec | 10 ++++-- 15 files changed, 271 insertions(+), 14 deletions(-) create mode 100644 lib/librarix/application.rb create mode 100644 lib/librarix/assets/application.scss create mode 100644 lib/librarix/public/application.css create mode 100644 lib/librarix/public/application.js create mode 100644 lib/librarix/redis.rb create mode 100644 lib/librarix/redis/movie.rb create mode 100644 lib/librarix/the_movie_db.rb create mode 100644 lib/librarix/views/application.js create mode 100644 lib/librarix/views/index.slim create mode 100644 lib/librarix/views/layout.slim create mode 100644 lib/librarix/views/movie.slim create mode 100644 lib/librarix/views/search.slim diff --git a/.gitignore b/.gitignore index ae3fdc2..f95080a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,6 @@ /.bundle/ -/.yardoc /Gemfile.lock -/_yardoc/ -/coverage/ -/doc/ -/pkg/ -/spec/reports/ /tmp/ *.bundle -*.so -*.o -*.a -mkmf.log +*.map +.sass-cache diff --git a/lib/librarix.rb b/lib/librarix.rb index 7e056be..528deb5 100644 --- a/lib/librarix.rb +++ b/lib/librarix.rb @@ -1,5 +1,15 @@ -require "librarix/version" +require 'librarix/version' +require 'librarix/redis' +require 'librarix/redis/movie' + +require 'librarix/application' module Librarix - # Your code goes here... + def self.redis + @redis ||= Librarix::Redis.new(::Redis.new) + end + + def self.redis=(connection, namespace: 'librarix') + @redis = Librarix::Redis.new(connection, namespace: namespace) + end end diff --git a/lib/librarix/application.rb b/lib/librarix/application.rb new file mode 100644 index 0000000..06ab228 --- /dev/null +++ b/lib/librarix/application.rb @@ -0,0 +1,42 @@ +require 'librarix/the_movie_db' + +require 'sinatra/base' +require 'sinatra/content_for' +require 'sinatra/json' + +require 'yaml' +require 'slim' +require 'themoviedb' + +module Librarix + class Application < Sinatra::Application + helpers Librarix::TheMovieDB + + get '/' do + slim :index, locals: {movies: Librarix::Redis::Movie.all.sort_by(&:release_date).reverse} + end + + get '/search' do + movies = params.key?('search') ? Tmdb::Movie.find(params['search']) : Tmdb::Movie.popular.map { |m| Tmdb::Movie.new(m) } + slim :search, locals: {movies: movies, conf: Tmdb::Configuration.new} + end + + post '/add' do + id = params[:id].to_i + movie = Tmdb::Movie.detail(id) + + if movie['status_code'] == 34 + elsif Librarix::Redis::Movie.new(id).added? + else + Librarix::Redis::Movie.new(id).add + end + redirect to('/') + end + + post '/remove' do + Librarix::Redis::Movie.new(params[:id]).remove + + redirect to('/') + end + end +end diff --git a/lib/librarix/assets/application.scss b/lib/librarix/assets/application.scss new file mode 100644 index 0000000..9fdbbea --- /dev/null +++ b/lib/librarix/assets/application.scss @@ -0,0 +1,35 @@ +body { + margin: 0; +} + +h2 { + margin-top: 0; +} + +ul { + list-style-type: none; + margin: 0; + padding: 0; + + li { + padding: 10px; + + display: flex; + flex-flow: row wrap; + align-items: center; + justify-content: center; + + .poster { + margin-right: 10px; + } + + .informations { + align-self: flex-start; + flex: 1 1 300px; + } + } + + li:nth-child(even) { + background-color: #f4f4f4; + } +} diff --git a/lib/librarix/public/application.css b/lib/librarix/public/application.css new file mode 100644 index 0000000..06fab10 --- /dev/null +++ b/lib/librarix/public/application.css @@ -0,0 +1 @@ +body{margin:0}h2{margin-top:0}ul{list-style-type:none;margin:0;padding:0}ul li{padding:10px;display:flex;flex-flow:row wrap;align-items:center;justify-content:center}ul li .poster{margin-right:10px}ul li .informations{align-self:flex-start;flex:1 1 300px}ul li:nth-child(even){background-color:#f4f4f4} diff --git a/lib/librarix/public/application.js b/lib/librarix/public/application.js new file mode 100644 index 0000000..5ddd9e1 --- /dev/null +++ b/lib/librarix/public/application.js @@ -0,0 +1,2 @@ +document.addEventListener('DOMContentLoaded', function(event) { +}); diff --git a/lib/librarix/redis.rb b/lib/librarix/redis.rb new file mode 100644 index 0000000..98510bf --- /dev/null +++ b/lib/librarix/redis.rb @@ -0,0 +1,49 @@ +require 'redis' + +module Librarix + class Redis + TTL = 10800 + + attr_reader :connection, :namespace + + def initialize(connection, namespace:) + @connection = connection + @namespace = namespace + end + + def exist?(key) + exists key + end + + def keys(pattern) + @connection.keys("#{prefix}#{pattern}").map { |key| key.sub(prefix, '') } + end + + def fetch(key, options = {}) + if options[:force] || (!exist?(key) && block_given?) + value = yield + set key, value + expire key, TTL if options.key?(:ttl) && options[:ttl] + + value + else + get key + end + end + + def respond_to?(name, include_all = false) + super || @connection.respond_to?(name, include_all) + end + + def method_missing(name, *args, &block) + return super unless @connection.respond_to?(name) + @connection.send(name, "#{prefix}#{args.shift}", *args) + end + + private + + def prefix + "#{namespace}:" + end + end +end diff --git a/lib/librarix/redis/movie.rb b/lib/librarix/redis/movie.rb new file mode 100644 index 0000000..42305b7 --- /dev/null +++ b/lib/librarix/redis/movie.rb @@ -0,0 +1,44 @@ +module Librarix + class Redis + class Movie + attr_reader :id + + def self.all + Array(Librarix.redis.smembers('movies_id')).map { |id| new(id).fetch } + end + + def initialize(id) + @id = id.to_i + end + + def add + Librarix.redis.sadd('movies_id', id) + fetch + end + + def added? + Librarix.redis.sismember('movies_id', id) + end + + def fetch(force = false) + data = JSON.parse(Librarix.redis.fetch("movie:#{id}", force: force) do + Tmdb::Movie.detail(id).to_json + end) + + Tmdb::Movie.new(data) + end + + def update + fetch(true) + end + + def remove + Librarix.redis.del("movie:#{id}") + Librarix.redis.srem('movies_id', id) + end + + def view + end + end + end +end diff --git a/lib/librarix/the_movie_db.rb b/lib/librarix/the_movie_db.rb new file mode 100644 index 0000000..8928cc1 --- /dev/null +++ b/lib/librarix/the_movie_db.rb @@ -0,0 +1,33 @@ +require 'themoviedb' + +module Librarix + module TheMovieDB + def poster_url(path, size = 'w92') + base_url = Librarix.redis.fetch('base_url', ttl: true) do + Tmdb::Configuration.new.base_url + end + + "#{base_url}#{size}#{path}" + end + + def movie(id) + Librarix::Redis::Movie.new(id).fetch + end + + module Movie + def release_date + @_release_date ||= Date.parse(super) unless super.nil? + end + + def release_year + release_date.year unless release_date.nil? + end + + def added? + Librarix::Redis::Movie.new(id).added? + end + end + end +end + +Tmdb::Movie.prepend Librarix::TheMovieDB::Movie diff --git a/lib/librarix/views/application.js b/lib/librarix/views/application.js new file mode 100644 index 0000000..e69de29 diff --git a/lib/librarix/views/index.slim b/lib/librarix/views/index.slim new file mode 100644 index 0000000..2584fa6 --- /dev/null +++ b/lib/librarix/views/index.slim @@ -0,0 +1,6 @@ +- content_for(:title) { 'Index' } + +ul + - movies.each do |movie| + li + == slim :movie, locals: {movie: movie} diff --git a/lib/librarix/views/layout.slim b/lib/librarix/views/layout.slim new file mode 100644 index 0000000..b51492e --- /dev/null +++ b/lib/librarix/views/layout.slim @@ -0,0 +1,11 @@ +doctype html +html + head + title = yield_content :title + meta charset="utf-8" + meta name="viewport" content="initial-scale=1.0, user-scalable=yes" + link rel="stylesheet" media="all" href="/application.css" + script type="text/javascript" src="/application.js" + body + div#main + == yield diff --git a/lib/librarix/views/movie.slim b/lib/librarix/views/movie.slim new file mode 100644 index 0000000..af8e1d3 --- /dev/null +++ b/lib/librarix/views/movie.slim @@ -0,0 +1,16 @@ +.poster + - if movie.poster_path + img src="#{poster_url(movie.poster_path, 'w154')}" +.informations + h2 + a href="https://www.themoviedb.org/movie/#{movie.id}" #{movie.original_title} (#{movie.release_year}) + p = movie.overview +.actions + - if movie.added? + form method="post" action="/remove" + input type="hidden" name="id" value="#{movie.id}" + button type="submit" Remove + - else + form method="post" action="/add" + input type="hidden" name="id" value="#{movie.id}" + button type="submit" Add diff --git a/lib/librarix/views/search.slim b/lib/librarix/views/search.slim new file mode 100644 index 0000000..33360a8 --- /dev/null +++ b/lib/librarix/views/search.slim @@ -0,0 +1,10 @@ +- content_for(:title) { 'Search' } + +form method="get" action="/search" + input type="text" name="search" value="#{params['search']}" + input type="submit" + +ul + - movies.each do |movie| + li + == slim :movie, locals: {movie: movie} diff --git a/librarix.gemspec b/librarix.gemspec index ed30211..1d30f04 100644 --- a/librarix.gemspec +++ b/librarix.gemspec @@ -8,8 +8,8 @@ Gem::Specification.new do |spec| spec.version = Librarix::VERSION spec.authors = ["Guillaume Dott"] spec.email = ["guillaume+github@dott.fr"] - spec.summary = %q{TODO: Write a short summary. Required.} - spec.description = %q{TODO: Write a longer description. Optional.} + spec.summary = %q{A simple webapp to manage your collections} + spec.description = %q{Manage all your collections in your browser and automatically fetch infos from TheMovieDB} spec.homepage = "" spec.license = "MIT" @@ -18,6 +18,12 @@ Gem::Specification.new do |spec| spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.require_paths = ["lib"] + spec.add_dependency "sinatra", '~> 1.4' + spec.add_dependency "sinatra-contrib", '~> 1.4' + spec.add_dependency "slim", '~> 3.0' + spec.add_dependency "redis", '~> 3.2' + spec.add_dependency "themoviedb", '~> 0.1' + spec.add_development_dependency "bundler", "~> 1.7" spec.add_development_dependency "rake", "~> 10.0" end