Remove views and replace redis with sequel
parent
46179cd27b
commit
eef60a8420
|
@ -0,0 +1,17 @@
|
||||||
|
Sequel.migration do
|
||||||
|
change do
|
||||||
|
create_table(:genres) do
|
||||||
|
primary_key :id
|
||||||
|
String :name, null: false
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table(:movies) do
|
||||||
|
primary_key :id
|
||||||
|
String :data, text: true, null: false
|
||||||
|
FalseClass :viewed, null: false, default: false
|
||||||
|
FalseClass :downloaded, null: false, default: false
|
||||||
|
end
|
||||||
|
|
||||||
|
create_join_table(movie_id: :movies, genre_id: :genres)
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,15 +1,11 @@
|
||||||
require 'librarix/version'
|
require 'librarix/version'
|
||||||
require 'librarix/redis'
|
|
||||||
require 'librarix/redis/movie'
|
|
||||||
|
|
||||||
|
require 'sequel'
|
||||||
|
require 'sqlite3'
|
||||||
|
require 'json'
|
||||||
|
|
||||||
|
Sequel::Model.plugin :json_serializer
|
||||||
|
Sequel::Model.db = Sequel.sqlite('librarix.sqlite')
|
||||||
|
|
||||||
|
require 'librarix/models'
|
||||||
require 'librarix/application'
|
require 'librarix/application'
|
||||||
|
|
||||||
module Librarix
|
|
||||||
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
|
|
||||||
|
|
|
@ -1,31 +1,17 @@
|
||||||
require 'librarix/filter'
|
|
||||||
require 'librarix/menu'
|
|
||||||
require 'librarix/the_movie_db'
|
|
||||||
require 'librarix/helpers'
|
|
||||||
|
|
||||||
require 'sinatra/base'
|
require 'sinatra/base'
|
||||||
require 'sinatra/content_for'
|
|
||||||
require 'sinatra/json'
|
require 'sinatra/json'
|
||||||
require 'sinatra/namespace'
|
require 'sinatra/namespace'
|
||||||
|
|
||||||
require 'yaml'
|
require 'yaml'
|
||||||
require 'slim'
|
|
||||||
require 'themoviedb'
|
require 'themoviedb'
|
||||||
|
|
||||||
module Librarix
|
module Librarix
|
||||||
class Application < Sinatra::Application
|
class Application < Sinatra::Application
|
||||||
def initialize(app = nil)
|
namespace '/api/v1' do
|
||||||
super
|
not_found do
|
||||||
|
{error: :not_found}.to_json
|
||||||
Librarix::Menu.menu.add 'Home', '/'
|
|
||||||
Librarix::Menu.menu.add 'Add a movie', '/search'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
helpers Librarix::TheMovieDB
|
|
||||||
helpers Librarix::Menu::Helper
|
|
||||||
helpers Librarix::Helpers
|
|
||||||
|
|
||||||
namespace '/api/v1' do
|
|
||||||
helpers do
|
helpers do
|
||||||
def base_url
|
def base_url
|
||||||
@base_url ||= "#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}"
|
@base_url ||= "#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}"
|
||||||
|
@ -44,11 +30,18 @@ module Librarix
|
||||||
content_type 'application/json'
|
content_type 'application/json'
|
||||||
end
|
end
|
||||||
|
|
||||||
get '/movies' do
|
namespace '/genres' do
|
||||||
|
get '' do
|
||||||
|
Librarix::Models::Genre.fetch.to_json
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
namespace '/movies' do
|
||||||
|
get '' do
|
||||||
Librarix::Filter.new(params).movies.to_json
|
Librarix::Filter.new(params).movies.to_json
|
||||||
end
|
end
|
||||||
|
|
||||||
post '/movies' do
|
post '' do
|
||||||
id = json_params['tmdb_id'].to_i
|
id = json_params['tmdb_id'].to_i
|
||||||
movie = Tmdb::Movie.detail(id)
|
movie = Tmdb::Movie.detail(id)
|
||||||
|
|
||||||
|
@ -57,88 +50,28 @@ module Librarix
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
get '/movies/:id' do |id|
|
get '/:id' do |id|
|
||||||
Librarix::Redis::Movie.new(id).fetch.to_json
|
Librarix::Models::Movie.find(id: id).to_json
|
||||||
end
|
end
|
||||||
|
|
||||||
get '/movies/:id/fetch' do |id|
|
get '/:id/fetch' do |id|
|
||||||
Librarix::Redis::Movie.new(id).update
|
Librarix::Models::Movie.fetch(85).to_json
|
||||||
end
|
end
|
||||||
|
|
||||||
patch '/movies/:id/view' do |id|
|
patch '/:id/view' do |id|
|
||||||
Librarix::Redis::Movie.new(params[:id]).view
|
Librarix::Models::Movie.find(id: id).view!
|
||||||
|
{success: true}.to_json
|
||||||
end
|
end
|
||||||
|
|
||||||
delete '/movies/:id' do |id|
|
patch '/:id/download' do |id|
|
||||||
Librarix::Redis::Movie.new(params[:id]).remove
|
Librarix::Models::Movie.find(id: id).download!
|
||||||
end
|
{success: true}.to_json
|
||||||
end
|
end
|
||||||
|
|
||||||
get '/' do
|
delete '/:id' do |id|
|
||||||
slim :index, locals: {filter: Librarix::Filter.new(params)}
|
Librarix::Models::Movie.find(id: id).destroy
|
||||||
|
{success: true}.to_json
|
||||||
end
|
end
|
||||||
|
|
||||||
get '/movie/:id' do |id|
|
|
||||||
movie = Librarix::Redis::Movie.new(id).fetch
|
|
||||||
|
|
||||||
if request.xhr?
|
|
||||||
slim :'partials/movie', layout: false, locals: {movie: movie}
|
|
||||||
else
|
|
||||||
slim :movie, locals: {movie: movie}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
get '/search' do
|
|
||||||
movies = if params['search'].nil?
|
|
||||||
Tmdb::Movie.popular.map { |m| Tmdb::Movie.new(m) }
|
|
||||||
elsif params['search'] == ''
|
|
||||||
[]
|
|
||||||
else
|
|
||||||
Tmdb::Movie.find(params['search'])
|
|
||||||
end
|
|
||||||
|
|
||||||
slim :search, locals: {movies: movies}
|
|
||||||
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 '/update' do
|
|
||||||
movie = Librarix::Redis::Movie.new(params[:id]).update
|
|
||||||
|
|
||||||
if request.xhr?
|
|
||||||
slim :'partials/movie', layout: false, locals: {movie: movie}
|
|
||||||
else
|
|
||||||
redirect to('/')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
post '/remove' do
|
|
||||||
Librarix::Redis::Movie.new(params[:id]).remove
|
|
||||||
|
|
||||||
if request.xhr?
|
|
||||||
""
|
|
||||||
else
|
|
||||||
redirect to('/')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
post '/view' do
|
|
||||||
Librarix::Redis::Movie.new(params[:id]).view
|
|
||||||
|
|
||||||
if request.xhr?
|
|
||||||
""
|
|
||||||
else
|
|
||||||
redirect to('/')
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,117 +0,0 @@
|
||||||
body {
|
|
||||||
margin: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
color: #666;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: #888;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
margin-top: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
|
|
||||||
font-size: 1.2em;
|
|
||||||
font-family: Verdana,Arial,sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
list-style-type: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul#menu {
|
|
||||||
display: flex;
|
|
||||||
flex-flow: row wrap;
|
|
||||||
justify-content: flex-end;
|
|
||||||
|
|
||||||
li {
|
|
||||||
margin: 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#search-genres ul {
|
|
||||||
display: flex;
|
|
||||||
flex-flow: row wrap;
|
|
||||||
|
|
||||||
li {
|
|
||||||
margin-right: 0.5em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.genres {
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
li {
|
|
||||||
margin-right: 0.4em;
|
|
||||||
}
|
|
||||||
|
|
||||||
li:last-child::after {
|
|
||||||
content: '';
|
|
||||||
}
|
|
||||||
|
|
||||||
li::after {
|
|
||||||
content: ',';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
form #search-main {
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
input {
|
|
||||||
border-radius: 0.4em;
|
|
||||||
border: solid 3px #f4f4f4;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="submit"] {
|
|
||||||
background-color: #f4f4f4;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="text"] {
|
|
||||||
flex-grow: 1;
|
|
||||||
min-width: 50px;
|
|
||||||
font-size: 1.4em;
|
|
||||||
padding: 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.default, .compact {
|
|
||||||
& > li {
|
|
||||||
padding: 10px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > li:nth-child(even) {
|
|
||||||
background-color: #f4f4f4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.movie {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.poster {
|
|
||||||
display: flex;
|
|
||||||
flex-flow: row wrap;
|
|
||||||
|
|
||||||
.movie {
|
|
||||||
width: 160px;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,90 +0,0 @@
|
||||||
module Librarix
|
|
||||||
class Filter
|
|
||||||
def self.filter_by_genre(movies, genres)
|
|
||||||
return movies if genres.empty?
|
|
||||||
movies.reject do |movie|
|
|
||||||
(movie.genres.map { |genre| genre['name'] } & genres).empty?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.filter_by_title(movies, title)
|
|
||||||
return movies unless title
|
|
||||||
movies.select { |movie| movie.title.downcase.include?(title) }
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.filter_by_view_state(movies, view_state)
|
|
||||||
if view_state == 'viewed'
|
|
||||||
movies.select(&:viewed?)
|
|
||||||
elsif view_state == 'not_viewed'
|
|
||||||
movies.reject(&:viewed?)
|
|
||||||
else
|
|
||||||
movies
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.sort(movies, sort)
|
|
||||||
if sort == 'date'
|
|
||||||
movies.sort_by(&:release_date).reverse
|
|
||||||
else
|
|
||||||
movies.sort_by(&:title)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.group(movies, group, sort)
|
|
||||||
return {all: movies} unless group
|
|
||||||
|
|
||||||
if sort == 'date'
|
|
||||||
movies.group_by { |movie| movie.release_date.year }
|
|
||||||
else
|
|
||||||
movies.group_by { |movie| movie.title[0].upcase }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
attr_reader :movies, :params
|
|
||||||
|
|
||||||
def initialize(params)
|
|
||||||
@params = params
|
|
||||||
end
|
|
||||||
|
|
||||||
def movies
|
|
||||||
@movies ||= begin
|
|
||||||
movies = Librarix::Redis::Movie.all
|
|
||||||
|
|
||||||
movies = self.class.filter_by_genre(movies, genres)
|
|
||||||
movies = self.class.filter_by_title(movies, params['title'])
|
|
||||||
movies = self.class.filter_by_view_state(movies, params['view_state'])
|
|
||||||
|
|
||||||
movies = self.class.sort(movies, sort)
|
|
||||||
movies = self.class.group(movies, group, sort)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def group
|
|
||||||
@group ||= params.key?('group') && params['group']
|
|
||||||
end
|
|
||||||
|
|
||||||
def genres
|
|
||||||
@genres ||= params.key?('genres') ? params['genres'].keys : []
|
|
||||||
end
|
|
||||||
|
|
||||||
def view_state
|
|
||||||
@view_state ||= if %w{all viewed not_viewed}.include?(params['view_state'])
|
|
||||||
params['view_state']
|
|
||||||
else
|
|
||||||
'all'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def sort
|
|
||||||
@sort ||= if %w{alphabetical date}.include?(params['sort'])
|
|
||||||
params['sort']
|
|
||||||
else
|
|
||||||
'date'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def maybe_search?
|
|
||||||
movies.all? { |k,v| v.empty? } && params.key?('title')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,11 +0,0 @@
|
||||||
module Librarix
|
|
||||||
module Helpers
|
|
||||||
def template
|
|
||||||
if %w{default compact poster}.include?(params['template'])
|
|
||||||
params['template']
|
|
||||||
else
|
|
||||||
'default'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,56 +0,0 @@
|
||||||
module Librarix
|
|
||||||
class Menu
|
|
||||||
module Helper
|
|
||||||
def menu
|
|
||||||
Librarix::Menu.menu.render request.path_info
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.menu
|
|
||||||
@menu ||= new
|
|
||||||
end
|
|
||||||
|
|
||||||
attr_accessor :menu
|
|
||||||
|
|
||||||
def initialize
|
|
||||||
self.menu = []
|
|
||||||
end
|
|
||||||
|
|
||||||
def add(name, url)
|
|
||||||
self.menu << Element.new(name, url)
|
|
||||||
end
|
|
||||||
|
|
||||||
def render(path = nil)
|
|
||||||
around menu.map { |elem| elem.render path }.join
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def around(content)
|
|
||||||
"<ul id=\"menu\">#{content}</ul>"
|
|
||||||
end
|
|
||||||
|
|
||||||
class Element
|
|
||||||
attr_accessor :name, :url
|
|
||||||
|
|
||||||
def initialize(name, url)
|
|
||||||
self.name = name
|
|
||||||
self.url = url
|
|
||||||
end
|
|
||||||
|
|
||||||
def render(path = nil)
|
|
||||||
around "<a href=\"#{url}\">#{name}</a>", path: path
|
|
||||||
end
|
|
||||||
|
|
||||||
def current?(path)
|
|
||||||
path == url
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def around(element, path: nil)
|
|
||||||
"<li#{current?(path) ? ' class="active"' : ''}>#{element}</li>"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
module Librarix::Models
|
||||||
|
end
|
||||||
|
|
||||||
|
require 'librarix/models/genre'
|
||||||
|
require 'librarix/models/movie'
|
|
@ -0,0 +1,15 @@
|
||||||
|
class Librarix::Models::Genre < Sequel::Model
|
||||||
|
def self.fetch
|
||||||
|
unrestrict_primary_key
|
||||||
|
|
||||||
|
genres = Tmdb::Genre.list['genres']
|
||||||
|
genres.each do |genre|
|
||||||
|
find_or_create(id: genre['id']) { |g| g.name = genre['name'] }
|
||||||
|
end
|
||||||
|
|
||||||
|
genres
|
||||||
|
end
|
||||||
|
|
||||||
|
many_to_many :movies
|
||||||
|
plugin :association_dependencies, movies: :nullify
|
||||||
|
end
|
|
@ -0,0 +1,37 @@
|
||||||
|
class Librarix::Models::Movie < Sequel::Model
|
||||||
|
def self.fetch(id)
|
||||||
|
unrestrict_primary_key
|
||||||
|
|
||||||
|
movie = find(id: id) || new(id: id)
|
||||||
|
movie.fetch!
|
||||||
|
end
|
||||||
|
|
||||||
|
plugin :serialization
|
||||||
|
serialize_attributes :json, :data
|
||||||
|
|
||||||
|
many_to_many :genres
|
||||||
|
plugin :association_dependencies, genres: :nullify
|
||||||
|
|
||||||
|
def fetch!
|
||||||
|
tmdb_data = Tmdb::Movie.detail(id)
|
||||||
|
self.data = tmdb_data
|
||||||
|
save
|
||||||
|
|
||||||
|
genres_id = data['genres'].map { |g| g['id'] }
|
||||||
|
Librarix::Models::Genre.where(id: genres_id).all.each do |genre|
|
||||||
|
add_genre(genre) unless genres.include?(genre)
|
||||||
|
end
|
||||||
|
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
def download!
|
||||||
|
self.downloaded = !downloaded
|
||||||
|
save
|
||||||
|
end
|
||||||
|
|
||||||
|
def view!
|
||||||
|
self.viewed = !viewed
|
||||||
|
save
|
||||||
|
end
|
||||||
|
end
|
|
@ -1 +0,0 @@
|
||||||
body{margin:10px}a{text-decoration:none;color:#666}a:hover{color:#888}h2{margin-top:0;overflow:hidden;text-overflow:ellipsis;font-size:1.2em;font-family:Verdana,Arial,sans-serif}ul{list-style-type:none;margin:0;padding:0}ul#menu{display:flex;flex-flow:row wrap;justify-content:flex-end}ul#menu li{margin:5px}#search-genres ul{display:flex;flex-flow:row wrap}#search-genres ul li{margin-right:0.5em}ul.genres{display:flex}ul.genres li{margin-right:0.4em}ul.genres li:last-child::after{content:''}ul.genres li::after{content:','}form #search-main{display:flex}form #search-main input{border-radius:0.4em;border:solid 3px #f4f4f4}form #search-main input[type="submit"]{background-color:#f4f4f4}form #search-main input[type="text"]{flex-grow:1;min-width:50px;font-size:1.4em;padding:5px}.default>li,.compact>li{padding:10px 0}.default>li:nth-child(even),.compact>li:nth-child(even){background-color:#f4f4f4}.default .movie,.compact .movie{display:flex;flex-flow:row wrap;align-items:center;justify-content:center}.default .movie .poster,.compact .movie .poster{margin-right:10px}.default .movie .informations,.compact .movie .informations{align-self:flex-start;flex:1 1 300px}.poster{display:flex;flex-flow:row wrap}.poster .movie{width:160px}
|
|
|
@ -1,82 +0,0 @@
|
||||||
function request(method, url, data, loadevent) {
|
|
||||||
var req = new XMLHttpRequest();
|
|
||||||
req.open(method, url);
|
|
||||||
req.setRequestHeader("X-Requested-With", "XMLHttpRequest");
|
|
||||||
|
|
||||||
req.addEventListener('load', loadevent);
|
|
||||||
|
|
||||||
req.send(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
function init() {
|
|
||||||
var movies = document.querySelectorAll('.movie');
|
|
||||||
for (var i = 0; i < movies.length; i++) {
|
|
||||||
new Movie(movies[i].dataset.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var Movie = function(id) {
|
|
||||||
this.id = parseInt(id);
|
|
||||||
this.element = document.querySelector('.movie[data-id="'+id+'"]');
|
|
||||||
|
|
||||||
var remove_button = this.element.querySelector('button[data-action="remove-movie"]');
|
|
||||||
var update_button = this.element.querySelector('button[data-action="update-movie"]');
|
|
||||||
var view_button = this.element.querySelector('button[data-action="view-movie"]');
|
|
||||||
|
|
||||||
if (remove_button) {
|
|
||||||
remove_button.addEventListener('click', function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
this.remove();
|
|
||||||
}.bind(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (update_button) {
|
|
||||||
update_button.addEventListener('click', function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
this.update();
|
|
||||||
}.bind(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (view_button) {
|
|
||||||
view_button.addEventListener('click', function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
this.view();
|
|
||||||
}.bind(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.formData = function() {
|
|
||||||
var data = new FormData();
|
|
||||||
data.append('id', this.id);
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.update = function() {
|
|
||||||
request('POST', '/update', this.formData(), function(e) {
|
|
||||||
oldelem = this.element;
|
|
||||||
|
|
||||||
tmp_elem = document.createElement('div');
|
|
||||||
tmp_elem.innerHTML = e.target.response;
|
|
||||||
|
|
||||||
this.element = tmp_elem.firstChild;
|
|
||||||
|
|
||||||
oldelem.parentNode.replaceChild(this.element, oldelem);
|
|
||||||
}.bind(this));
|
|
||||||
};
|
|
||||||
|
|
||||||
this.remove = function() {
|
|
||||||
request('POST', '/remove', this.formData(), function(e) {
|
|
||||||
this.element.parentNode.remove();
|
|
||||||
}.bind(this));
|
|
||||||
};
|
|
||||||
|
|
||||||
this.view = function() {
|
|
||||||
request('POST', '/view', this.formData(), function(e) {
|
|
||||||
this.element.querySelector('button[data-action="view-movie"]').parentNode.remove();
|
|
||||||
}.bind(this));
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function(event) {
|
|
||||||
init();
|
|
||||||
});
|
|
|
@ -1,49 +0,0 @@
|
||||||
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
|
|
|
@ -1,64 +0,0 @@
|
||||||
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 self.genres
|
|
||||||
fetch_genres unless Librarix.redis.exists('genres')
|
|
||||||
Librarix.redis.smembers('genres').sort
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.fetch_genres
|
|
||||||
Tmdb::Genre.list['genres'].each do |genre|
|
|
||||||
Librarix.redis.sadd('genres', genre['name'])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def initialize(id)
|
|
||||||
@id = id.to_i
|
|
||||||
end
|
|
||||||
|
|
||||||
def movie
|
|
||||||
@movie ||= fetch
|
|
||||||
end
|
|
||||||
|
|
||||||
def add
|
|
||||||
Librarix.redis.sadd('movies_id', id)
|
|
||||||
movie
|
|
||||||
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
|
|
||||||
Librarix.redis.sadd('viewed_movies_id', id)
|
|
||||||
end
|
|
||||||
|
|
||||||
def viewed?
|
|
||||||
Librarix.redis.sismember('viewed_movies_id', id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,41 +0,0 @@
|
||||||
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 genres
|
|
||||||
super || []
|
|
||||||
end
|
|
||||||
|
|
||||||
def release_date
|
|
||||||
@_release_date ||= Date.parse(super) unless super.nil? || super.empty?
|
|
||||||
end
|
|
||||||
|
|
||||||
def release_year
|
|
||||||
release_date.year unless release_date.nil?
|
|
||||||
end
|
|
||||||
|
|
||||||
def added?
|
|
||||||
Librarix::Redis::Movie.new(id).added?
|
|
||||||
end
|
|
||||||
|
|
||||||
def viewed?
|
|
||||||
Librarix::Redis::Movie.new(id).viewed?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
Tmdb::Movie.prepend Librarix::TheMovieDB::Movie
|
|
|
@ -1,39 +0,0 @@
|
||||||
- content_for :title do
|
|
||||||
| Movies
|
|
||||||
|
|
||||||
form method="get" action="/" id="filter"
|
|
||||||
div id="search-main"
|
|
||||||
input type="text" name="title" value="#{params['title']}" autocomplete="off"
|
|
||||||
input type="submit" value="Filter"
|
|
||||||
div id="search-more"
|
|
||||||
select name="view_state"
|
|
||||||
option value="all" selected=(filter.view_state == 'all') All movies
|
|
||||||
option value="viewed" selected=(filter.view_state == 'viewed') Only viewed
|
|
||||||
option value="not_viewed" selected=(filter.view_state == 'not_viewed') Not viewed
|
|
||||||
select name="sort"
|
|
||||||
option value="alphabetical" selected=(filter.sort == 'alphabetical') Alphabetical
|
|
||||||
option value="date" selected=(filter.sort == 'date') Release date
|
|
||||||
input type="checkbox" name="group" id="group" checked=(filter.group)
|
|
||||||
label for="group" Group by sort
|
|
||||||
select name="template"
|
|
||||||
option value="default" selected=(template == 'default') Default
|
|
||||||
option value="compact" selected=(template == 'compact') Compact
|
|
||||||
option value="poster" selected=(template == 'poster') Poster
|
|
||||||
div id="search-genres"
|
|
||||||
ul
|
|
||||||
- Librarix::Redis::Movie.genres.each do |genre|
|
|
||||||
li
|
|
||||||
input type="checkbox" name="genres[#{genre}]" id="#{genre}" checked=(filter.genres.include?(genre))
|
|
||||||
label for="#{genre}" = genre
|
|
||||||
|
|
||||||
|
|
||||||
- filter.movies.each do |group, movies|
|
|
||||||
- unless group == :all
|
|
||||||
h1 = group
|
|
||||||
== slim :'partials/list', locals: {movies: movies}
|
|
||||||
- if filter.maybe_search?
|
|
||||||
p
|
|
||||||
| Search for
|
|
||||||
strong
|
|
||||||
a<> href="#{url("/search?search=#{params['title']}")}" = params['title']
|
|
||||||
| ?
|
|
|
@ -1,13 +0,0 @@
|
||||||
doctype html
|
|
||||||
html
|
|
||||||
head
|
|
||||||
title
|
|
||||||
= yield_content :title
|
|
||||||
| - Librarix
|
|
||||||
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
|
|
||||||
== menu
|
|
||||||
== yield
|
|
|
@ -1,27 +0,0 @@
|
||||||
- content_for :title do
|
|
||||||
= movie.title
|
|
||||||
|
|
||||||
.movie data-id="#{movie.id}"
|
|
||||||
h1 = movie.title
|
|
||||||
.poster
|
|
||||||
- if movie.poster_path
|
|
||||||
img src="#{poster_url(movie.poster_path, 'w154')}"
|
|
||||||
.informations
|
|
||||||
p = movie.release_date
|
|
||||||
p = movie.overview
|
|
||||||
p
|
|
||||||
a> href="https://www.themoviedb.org/movie/#{movie.id}" The Movie DB
|
|
||||||
| (#{movie.vote_average}/10, #{movie.vote_count} votes)
|
|
||||||
.actions
|
|
||||||
- if movie.added?
|
|
||||||
- unless movie.viewed?
|
|
||||||
form method="post" action="/view"
|
|
||||||
input type="hidden" name="id" value="#{movie.id}"
|
|
||||||
button type="submit" data-action="view-movie" View
|
|
||||||
form method="post" action="/remove"
|
|
||||||
input type="hidden" name="id" value="#{movie.id}"
|
|
||||||
button type="submit" data-action="remove-movie" Remove
|
|
||||||
- else
|
|
||||||
form method="post" action="/add"
|
|
||||||
input type="hidden" name="id" value="#{movie.id}"
|
|
||||||
button type="submit" data-action="add-movie" Add
|
|
|
@ -1,4 +0,0 @@
|
||||||
ul.movies class="#{template}"
|
|
||||||
- movies.each do |movie|
|
|
||||||
li
|
|
||||||
== slim :'partials/movie', locals: {movie: movie}
|
|
|
@ -1,2 +0,0 @@
|
||||||
.movie data-id="#{movie.id}"
|
|
||||||
== slim :"partials/movie/#{template}", locals: {movie: movie}
|
|
|
@ -1,19 +0,0 @@
|
||||||
.poster
|
|
||||||
- if movie.poster_path
|
|
||||||
img src="#{poster_url(movie.poster_path, 'w92')}"
|
|
||||||
.informations
|
|
||||||
h2
|
|
||||||
a href="#{url("/movie/#{movie.id}")}" #{movie.title}
|
|
||||||
.actions
|
|
||||||
- if movie.added?
|
|
||||||
- unless movie.viewed?
|
|
||||||
form method="post" action="/view"
|
|
||||||
input type="hidden" name="id" value="#{movie.id}"
|
|
||||||
button type="submit" data-action="view-movie" View
|
|
||||||
form method="post" action="/remove"
|
|
||||||
input type="hidden" name="id" value="#{movie.id}"
|
|
||||||
button type="submit" data-action="remove-movie" Remove
|
|
||||||
- else
|
|
||||||
form method="post" action="/add"
|
|
||||||
input type="hidden" name="id" value="#{movie.id}"
|
|
||||||
button type="submit" data-action="add-movie" Add
|
|
|
@ -1,27 +0,0 @@
|
||||||
.poster
|
|
||||||
- if movie.poster_path
|
|
||||||
img src="#{poster_url(movie.poster_path, 'w154')}"
|
|
||||||
.informations
|
|
||||||
h2
|
|
||||||
a href="#{url("/movie/#{movie.id}")}" #{movie.title}
|
|
||||||
p = movie.release_date
|
|
||||||
p = movie.overview
|
|
||||||
ul.genres
|
|
||||||
- movie.genres.each do |genre|
|
|
||||||
li = genre['name']
|
|
||||||
.actions
|
|
||||||
- if movie.added?
|
|
||||||
- unless movie.viewed?
|
|
||||||
form method="post" action="/view"
|
|
||||||
input type="hidden" name="id" value="#{movie.id}"
|
|
||||||
button type="submit" data-action="view-movie" View
|
|
||||||
form method="post" action="/update"
|
|
||||||
input type="hidden" name="id" value="#{movie.id}"
|
|
||||||
button type="submit" data-action="update-movie" Update
|
|
||||||
form method="post" action="/remove"
|
|
||||||
input type="hidden" name="id" value="#{movie.id}"
|
|
||||||
button type="submit" data-action="remove-movie" Remove
|
|
||||||
- else
|
|
||||||
form method="post" action="/add"
|
|
||||||
input type="hidden" name="id" value="#{movie.id}"
|
|
||||||
button type="submit" data-action="add-movie" Add
|
|
|
@ -1,7 +0,0 @@
|
||||||
.poster
|
|
||||||
- if movie.poster_path
|
|
||||||
a href="#{url("/movie/#{movie.id}")}"
|
|
||||||
img src="#{poster_url(movie.poster_path, 'w154')}"
|
|
||||||
.informations
|
|
||||||
h2
|
|
||||||
a href="#{url("/movie/#{movie.id}")}" #{movie.title}
|
|
|
@ -1,10 +0,0 @@
|
||||||
- content_for :title do
|
|
||||||
| Search
|
|
||||||
|
|
||||||
form method="get" action="/search" id="search"
|
|
||||||
div id="search-main"
|
|
||||||
input type="text" name="search" value="#{params['search']}" autocomplete="off" autofocus="on"
|
|
||||||
input type="submit" value="Search"
|
|
||||||
|
|
||||||
div
|
|
||||||
== slim :'partials/list', locals: {movies: movies}
|
|
|
@ -20,11 +20,11 @@ Gem::Specification.new do |spec|
|
||||||
|
|
||||||
spec.add_dependency "sinatra", '~> 2.0'
|
spec.add_dependency "sinatra", '~> 2.0'
|
||||||
spec.add_dependency "sinatra-contrib", '~> 2.0'
|
spec.add_dependency "sinatra-contrib", '~> 2.0'
|
||||||
spec.add_dependency "slim", '~> 3.0'
|
spec.add_dependency "sequel", '~> 5.21'
|
||||||
spec.add_dependency "redis", '~> 3.2'
|
spec.add_dependency "sqlite3", '~> 1.4'
|
||||||
spec.add_dependency "themoviedb", '~> 0.1'
|
spec.add_dependency "themoviedb", '~> 1.0'
|
||||||
|
|
||||||
spec.add_development_dependency "bundler", "~> 2.0"
|
spec.add_development_dependency "bundler", "~> 2.0"
|
||||||
spec.add_development_dependency "rake", "~> 10.0"
|
spec.add_development_dependency "rake", "~> 10.0"
|
||||||
spec.add_development_dependency "sass", "~> 3.4"
|
spec.add_development_dependency "irb"
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue