# SPDX-License-Identifier: AGPL-3.0-only # SPDX-FileCopyrightText: 2023 Hugo Peixoto require 'sinatra' require './database.rb' require './models.rb' def h(bytes) if bytes < 2**10 "#{bytes} bytes" elsif bytes < 2**20 "%.2f KiB" % (1.0 * bytes / 2**10) elsif bytes < 2**30 "%.2f MiB" % (1.0 * bytes / 2**20) elsif bytes < 2**40 "%.2f GiB" % (1.0 * bytes / 2**30) else "%.2f TiB" % (1.0 * bytes / 2**40) end end def attempt(attempts, &block) begin block.call rescue if attempts > 1 attempts -= 1 retry else raise end end end set :public_folder, __dir__ + '/public' get '/' do downloads = ActiveRecord::Base.connection.execute(" SELECT COUNT(1) AS total, SUM(size) AS bytes FROM (select MAX(size) AS size from downloads group by video_id) as x; ")[0] videos = ActiveRecord::Base.connection.execute("select count(1) AS total from videos;")[0] users = ActiveRecord::Base.connection.execute("select count(distinct email) AS total from downloads;")[0] downloads_per_user = ActiveRecord::Base.connection.execute("select SUM(size) AS size, COUNT(1) AS total FROM (select email, video_id, MAX(size) as size from downloads group by email, video_id) x GROUP BY email ORDER BY 1 DESC;") stats = { videos_known: videos["total"].to_i, videos_downloaded: downloads["total"].to_i, bytes_downloaded: downloads["bytes"].to_i, downloads_per_user: downloads_per_user, users: users["total"], } ERB .new(File.read("index.html.erb"), trim_mode: "<>-") .result_with_hash(stats) end get '/videos.json' do content_type 'application/json' amount = params['amount'].to_i if amount > 100_000 { error: "greedy" }.to_json else videos = Video .left_outer_joins(:downloads) .group("randname") .order("COUNT(downloads.video_id) ASC, RANDOM()") .limit(amount) .pluck(:randname) { videos: videos }.to_json end end post '/video' do content_type 'application/json' data = JSON.parse(request.body.read) attempt(10) do Download.create!( video: Video.find_by!(randname: data["video_id"]), size: data["size"], sha256: data["sha256"], email: data["email"], ) end { status: 'ok' }.to_json end post '/check' do content_type 'application/json' ids = JSON.parse(request.body.read) videos = Video .left_outer_joins(:downloads) .where(randname: ids) .pluck(:randname, :sha256, :size) .map { |v| %w[randname sha256 size].zip(v).to_h } { videos: videos }.to_json end get '/config.json' do content_type 'application/json' { videos_url: "https://sapo.pxto.pt/videos.json", upload_url: "https://sapo.pxto.pt/video", check_url: "https://sapo.pxto.pt/check", max_amount: 100_000, }.to_json end