sapo-videos/main.rb

125 lines
2.8 KiB
Ruby

# SPDX-License-Identifier: AGPL-3.0-only
# SPDX-FileCopyrightText: 2023 Hugo Peixoto <hugo.peixoto@gmail.com>
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 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