basic song downloader backend
This commit is contained in:
parent
1427aa6fc1
commit
b67a3c350e
|
@ -5,3 +5,4 @@
|
||||||
.env
|
.env
|
||||||
/crystalgauntlet.db
|
/crystalgauntlet.db
|
||||||
/config.toml
|
/config.toml
|
||||||
|
/data/
|
|
@ -10,7 +10,7 @@ you may need to head into `lib/` to fix deps. i'm Very sorry
|
||||||
|
|
||||||
## setup
|
## setup
|
||||||
|
|
||||||
copy `.env.example` to `.env` and fill it out, same for `config.toml.example` -> `config.toml`
|
copy `.env.example` to `.env` and fill it out, same for `config.example.toml` -> `config.toml`
|
||||||
|
|
||||||
run `cake db:migrate` (must have [cake](https://github.com/axvm/cake/))
|
run `cake db:migrate` (must have [cake](https://github.com/axvm/cake/))
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
[general]
|
||||||
|
# if this path is encountered during path traversal,
|
||||||
|
# it will be removed. this is useful for instances
|
||||||
|
# where your absolute domain path is not long enough
|
||||||
|
# to replace boomlings.com, because you can then point
|
||||||
|
# it at a different, longer path to fill the gap
|
||||||
|
#
|
||||||
|
# example:
|
||||||
|
# boomlings.com/database/
|
||||||
|
# example.com/aaaaaaaaaa/
|
||||||
|
# ^^^^^^^^^^^
|
||||||
|
#
|
||||||
|
# leaving blank will disable this
|
||||||
|
append_path = ""
|
||||||
|
|
||||||
|
[formatting]
|
||||||
|
# whether to format dates as relative or absolute
|
||||||
|
# "relative" = relative, "absolute" = absolute
|
||||||
|
# do note that absolute times can result in uglier
|
||||||
|
# times due to colons being forbiddne in certain
|
||||||
|
# spots
|
||||||
|
date = "relative"
|
||||||
|
|
||||||
|
[accounts]
|
||||||
|
# allow new accounts to be created
|
||||||
|
allow_registration = true
|
||||||
|
|
||||||
|
[voting]
|
||||||
|
# allow votes to influence a level's difficulty when it
|
||||||
|
# hasn't been set yet. when set to false, all unrated
|
||||||
|
# levels will be NA
|
||||||
|
allow_votes = true
|
||||||
|
# same as above, but for demon difficulties
|
||||||
|
# this will let people vote and influence a demon'S
|
||||||
|
# difficulty past its original demon rating
|
||||||
|
allow_demon_votes = true
|
||||||
|
# the minimum amount of votes before a level's difficulty
|
||||||
|
# will go from NA to the average
|
||||||
|
min_votes = 10
|
||||||
|
# same as above, but for demon ratings
|
||||||
|
min_demon_votes = 10
|
||||||
|
|
||||||
|
[levels]
|
||||||
|
# prevent users from deleting their own levels
|
||||||
|
# if they are rated
|
||||||
|
prevent_deletion_rated = true
|
||||||
|
# prevent users from deleting their own levels
|
||||||
|
# if they are featured
|
||||||
|
prevent_deletion_featured = true
|
||||||
|
|
||||||
|
[songs]
|
||||||
|
# allow custom songs in general to be used,
|
||||||
|
# whether it be non-newgrounds or newgrounds ones
|
||||||
|
allow_custom_songs = true
|
||||||
|
# allow non-newgrounds custom songs to be used
|
||||||
|
# on the server
|
||||||
|
allow_nong_songs = true
|
||||||
|
# pushes all non-newgrounds songs above an arbitrary
|
||||||
|
# id to prevent collisions with newgrounds ids, meaning
|
||||||
|
# all song ids that work in vanilla GD will work
|
||||||
|
# on the server
|
||||||
|
preserve_newgrounds_ids = true
|
||||||
|
|
||||||
|
[songs.sources]
|
||||||
|
# allow ALL sources that yt-dlp supports for music
|
||||||
|
# this is a BAD idea for many reasons
|
||||||
|
allow_all_sources = false
|
||||||
|
|
||||||
|
# lets you support much more sites but may result in much
|
||||||
|
# slower download speeds and more bandwidth. requires ffmpeg
|
||||||
|
allow_transcoding = true
|
||||||
|
|
||||||
|
# location of your yt-dlp binary. get one here: https://github.com/yt-dlp/yt-dlp/releases/tag/2022.11.11
|
||||||
|
# defaults to checking through path
|
||||||
|
ytdlp_binary = "/usr/bin/yt-dlp"
|
||||||
|
|
||||||
|
# location of your ffmpeg binary. get one here: https://ffmpeg.org/download.html
|
||||||
|
# allows for transcoding
|
||||||
|
# defaults to checking through path
|
||||||
|
ffmpeg_binary = "/usr/bin/ffmpeg"
|
||||||
|
|
||||||
|
# leads to more stable downloads at the cost of
|
||||||
|
# using up much more storage to store every song
|
||||||
|
#
|
||||||
|
# required for allow_transcoding
|
||||||
|
proxy_downloads = true
|
||||||
|
|
||||||
|
# expressed in seconds, doesn't affect NG
|
||||||
|
max_duration = 600
|
||||||
|
|
||||||
|
# see: https://github.com/yt-dlp/yt-dlp/blob/master/supportedsites.md
|
||||||
|
# not every source is supported, and most video sites will fail w/o transcoding enabled
|
||||||
|
[songs.sources.youtube]
|
||||||
|
allow = true
|
||||||
|
|
||||||
|
[songs.sources.soundcloud]
|
||||||
|
allow = true
|
||||||
|
|
||||||
|
[songs.sources.generic]
|
||||||
|
# direct URLs and similar
|
||||||
|
allow = true
|
|
@ -1,49 +0,0 @@
|
||||||
[general]
|
|
||||||
# if this path is encountered during path traversal,
|
|
||||||
# it will be removed. this is useful for instances
|
|
||||||
# where your absolute domain path is not long enough
|
|
||||||
# to replace boomlings.com, because you can then point
|
|
||||||
# it at a different, longer path to fill the gap
|
|
||||||
#
|
|
||||||
# example:
|
|
||||||
# boomlings.com/database/
|
|
||||||
# example.com/aaaaaaaaaa/
|
|
||||||
# ^^^^^^^^^^^
|
|
||||||
#
|
|
||||||
# leaving blank will disable this
|
|
||||||
append_path = ""
|
|
||||||
|
|
||||||
[formatting]
|
|
||||||
# whether to format dates as relative or absolute
|
|
||||||
# "relative" = relative, "absolute" = absolute
|
|
||||||
# do note that absolute times can result in uglier
|
|
||||||
# times due to colons being forbiddne in certain
|
|
||||||
# spots
|
|
||||||
date = "relative"
|
|
||||||
|
|
||||||
[accounts]
|
|
||||||
# allow new accounts to be created
|
|
||||||
allow_registration = true
|
|
||||||
|
|
||||||
[voting]
|
|
||||||
# allow votes to influence a level's difficulty when it
|
|
||||||
# hasn't been set yet. when set to false, all unrated
|
|
||||||
# levels will be NA
|
|
||||||
allow_votes = true
|
|
||||||
# same as above, but for demon difficulties
|
|
||||||
# this will let people vote and influence a demon'S
|
|
||||||
# difficulty past its original demon rating
|
|
||||||
allow_demon_votes = true
|
|
||||||
# the minimum amount of votes before a level's difficulty
|
|
||||||
# will go from NA to the average
|
|
||||||
min_votes = 10
|
|
||||||
# same as above, but for demon ratings
|
|
||||||
min_demon_votes = 10
|
|
||||||
|
|
||||||
[levels]
|
|
||||||
# prevent users from deleting their own levels
|
|
||||||
# if they are rated
|
|
||||||
prevent_deletion_rated = true
|
|
||||||
# prevent users from deleting their own levels
|
|
||||||
# if they are featured
|
|
||||||
prevent_deletion_featured = true
|
|
|
@ -72,6 +72,9 @@ module CrystalGauntlet
|
||||||
server.bind_unix(listen_on.to_s.sub("unix://",""))
|
server.bind_unix(listen_on.to_s.sub("unix://",""))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# for debugging
|
||||||
|
#Songs.reupload("https://soundcloud.com/koraii/encroachingdark", 123456)
|
||||||
|
|
||||||
puts "Listening on #{listen_on.to_s}"
|
puts "Listening on #{listen_on.to_s}"
|
||||||
server.listen
|
server.listen
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,14 +1,76 @@
|
||||||
|
require "json"
|
||||||
|
|
||||||
include CrystalGauntlet
|
include CrystalGauntlet
|
||||||
|
|
||||||
module CrystalGauntlet::Songs
|
module CrystalGauntlet::Songs
|
||||||
extend self
|
extend self
|
||||||
|
|
||||||
|
GD_AUDIO_FORMAT = "mp3"
|
||||||
|
|
||||||
def is_custom_song(id)
|
def is_custom_song(id)
|
||||||
id >= 50
|
id >= 50
|
||||||
end
|
end
|
||||||
|
|
||||||
def is_reuploaded_song(id)
|
def is_reuploaded_song(id)
|
||||||
# todo: make configurable
|
|
||||||
id >= 5000000
|
id >= 5000000
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class Song
|
||||||
|
def initialize(name : String, author : String, size : Int32, download_url : String | Nil, normalized_url : String)
|
||||||
|
@name = name
|
||||||
|
@author = author
|
||||||
|
@size = size
|
||||||
|
@download_url = download_url
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def is_source_allowed(source : String) : Bool
|
||||||
|
config_get("songs.allow_all_sources").as?(Bool) || config_get("songs.sources.#{source}.allow").as?(Bool) || false
|
||||||
|
end
|
||||||
|
|
||||||
|
def reupload(url : String, id : Int32) : Song | Nil
|
||||||
|
puts url
|
||||||
|
|
||||||
|
output = IO::Memory.new
|
||||||
|
# todo: ⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️ LOOK OUT FOR SHELL INJECTION BULLSHIT!!!!!!!!!!!!!!!!!!
|
||||||
|
Process.run(config_get("songs.sources.ytdlp_binary").as?(String) || "yt-dlp", ["-J", url], output: output)
|
||||||
|
output.close
|
||||||
|
|
||||||
|
puts output.to_s
|
||||||
|
|
||||||
|
metadata = JSON.parse(output.to_s)
|
||||||
|
|
||||||
|
if !is_source_allowed(metadata["extractor"].as_s? || "unknown")
|
||||||
|
raise "source forbidden: #{metadata["extractor"]}"
|
||||||
|
end
|
||||||
|
|
||||||
|
max_duration = config_get("songs.sources.max_duration").as?(Int64) || 0
|
||||||
|
|
||||||
|
if max_duration > 0
|
||||||
|
if !metadata["duration"]
|
||||||
|
raise "failed to determine track duration"
|
||||||
|
elsif metadata["duration"].as_f >= max_duration
|
||||||
|
raise "track goes above max track duration (#{max_duration}s)"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if config_get("songs.sources.allow_transcoding")
|
||||||
|
if !config_get("songs.sources.proxy_downloads").as?(Bool)
|
||||||
|
raise "can't download a song with transcoding but without proxying allowed"
|
||||||
|
end
|
||||||
|
|
||||||
|
canonical_url = metadata["webpage_url"].as_s? || metadata["original_url"].as_s? || url
|
||||||
|
|
||||||
|
target_path = Path.new("data", "#{id}.mp3")
|
||||||
|
|
||||||
|
Process.run(config_get("songs.sources.ytdlp_binary").as?(String) || "yt-dlp", ["-f", "ba", "-x", "--audio-format", GD_AUDIO_FORMAT, "-o", target_path.to_s, "--ffmpeg-location", config_get("songs.sources.ffmpeg_binary").as?(String) || "ffmpeg", canonical_url], output: STDOUT, error: STDOUT)
|
||||||
|
|
||||||
|
size = File.size(target_path)
|
||||||
|
|
||||||
|
# todo: don't point to localhost
|
||||||
|
Song.new(metadata["fulltitle"].as_s? || metadata["title"].as_s? || "Song", metadata["uploader"].as_s? || "", size.to_i32, "http://localhost:8080/#{id}.mp3", canonical_url)
|
||||||
|
else
|
||||||
|
# todo
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue