forked from midou/invidious
Add option to configure default user preferences
This commit is contained in:
parent
1fd7ff5655
commit
bd4f5ebcdf
@ -1198,22 +1198,22 @@ post "/preferences" do |env|
|
|||||||
local = local == "on"
|
local = local == "on"
|
||||||
|
|
||||||
speed = env.params.body["speed"]?.try &.as(String).to_f?
|
speed = env.params.body["speed"]?.try &.as(String).to_f?
|
||||||
speed ||= DEFAULT_USER_PREFERENCES.speed
|
speed ||= CONFIG.default_user_preferences.speed
|
||||||
|
|
||||||
quality = env.params.body["quality"]?.try &.as(String)
|
quality = env.params.body["quality"]?.try &.as(String)
|
||||||
quality ||= DEFAULT_USER_PREFERENCES.quality
|
quality ||= CONFIG.default_user_preferences.quality
|
||||||
|
|
||||||
volume = env.params.body["volume"]?.try &.as(String).to_i?
|
volume = env.params.body["volume"]?.try &.as(String).to_i?
|
||||||
volume ||= DEFAULT_USER_PREFERENCES.volume
|
volume ||= CONFIG.default_user_preferences.volume
|
||||||
|
|
||||||
comments = [] of String
|
comments = [] of String
|
||||||
2.times do |i|
|
2.times do |i|
|
||||||
comments << (env.params.body["comments[#{i}]"]?.try &.as(String) || DEFAULT_USER_PREFERENCES.comments[i])
|
comments << (env.params.body["comments[#{i}]"]?.try &.as(String) || CONFIG.default_user_preferences.comments[i])
|
||||||
end
|
end
|
||||||
|
|
||||||
captions = [] of String
|
captions = [] of String
|
||||||
3.times do |i|
|
3.times do |i|
|
||||||
captions << (env.params.body["captions[#{i}]"]?.try &.as(String) || DEFAULT_USER_PREFERENCES.captions[i])
|
captions << (env.params.body["captions[#{i}]"]?.try &.as(String) || CONFIG.default_user_preferences.captions[i])
|
||||||
end
|
end
|
||||||
|
|
||||||
related_videos = env.params.body["related_videos"]?.try &.as(String)
|
related_videos = env.params.body["related_videos"]?.try &.as(String)
|
||||||
@ -1225,7 +1225,7 @@ post "/preferences" do |env|
|
|||||||
redirect_feed = redirect_feed == "on"
|
redirect_feed = redirect_feed == "on"
|
||||||
|
|
||||||
locale = env.params.body["locale"]?.try &.as(String)
|
locale = env.params.body["locale"]?.try &.as(String)
|
||||||
locale ||= DEFAULT_USER_PREFERENCES.locale
|
locale ||= CONFIG.default_user_preferences.locale
|
||||||
|
|
||||||
dark_mode = env.params.body["dark_mode"]?.try &.as(String)
|
dark_mode = env.params.body["dark_mode"]?.try &.as(String)
|
||||||
dark_mode ||= "off"
|
dark_mode ||= "off"
|
||||||
@ -1236,10 +1236,10 @@ post "/preferences" do |env|
|
|||||||
thin_mode = thin_mode == "on"
|
thin_mode = thin_mode == "on"
|
||||||
|
|
||||||
max_results = env.params.body["max_results"]?.try &.as(String).to_i?
|
max_results = env.params.body["max_results"]?.try &.as(String).to_i?
|
||||||
max_results ||= DEFAULT_USER_PREFERENCES.max_results
|
max_results ||= CONFIG.default_user_preferences.max_results
|
||||||
|
|
||||||
sort = env.params.body["sort"]?.try &.as(String)
|
sort = env.params.body["sort"]?.try &.as(String)
|
||||||
sort ||= DEFAULT_USER_PREFERENCES.sort
|
sort ||= CONFIG.default_user_preferences.sort
|
||||||
|
|
||||||
latest_only = env.params.body["latest_only"]?.try &.as(String)
|
latest_only = env.params.body["latest_only"]?.try &.as(String)
|
||||||
latest_only ||= "off"
|
latest_only ||= "off"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
struct InvidiousChannel
|
struct InvidiousChannel
|
||||||
add_mapping({
|
db_mapping({
|
||||||
id: String,
|
id: String,
|
||||||
author: String,
|
author: String,
|
||||||
updated: Time,
|
updated: Time,
|
||||||
@ -9,7 +9,7 @@ struct InvidiousChannel
|
|||||||
end
|
end
|
||||||
|
|
||||||
struct ChannelVideo
|
struct ChannelVideo
|
||||||
add_mapping({
|
db_mapping({
|
||||||
id: String,
|
id: String,
|
||||||
title: String,
|
title: String,
|
||||||
published: Time,
|
published: Time,
|
||||||
|
@ -1,4 +1,76 @@
|
|||||||
|
require "./macros"
|
||||||
|
|
||||||
|
struct ConfigPreferences
|
||||||
|
module StringToArray
|
||||||
|
def self.to_yaml(value : Array(String), yaml : YAML::Nodes::Builder)
|
||||||
|
yaml.sequence do
|
||||||
|
value.each do |element|
|
||||||
|
yaml.scalar element
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.from_yaml(ctx : YAML::ParseContext, node : YAML::Nodes::Node) : Array(String)
|
||||||
|
begin
|
||||||
|
unless node.is_a?(YAML::Nodes::Sequence)
|
||||||
|
node.raise "Expected sequence, not #{node.class}"
|
||||||
|
end
|
||||||
|
|
||||||
|
result = [] of String
|
||||||
|
node.nodes.each do
|
||||||
|
unless node.is_a?(YAML::Nodes::Scalar)
|
||||||
|
node.raise "Expected scalar, not #{node.class}"
|
||||||
|
end
|
||||||
|
|
||||||
|
result << node.value
|
||||||
|
end
|
||||||
|
rescue ex
|
||||||
|
if node.is_a?(YAML::Nodes::Scalar)
|
||||||
|
result = [node.value, ""]
|
||||||
|
else
|
||||||
|
result = ["", ""]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
yaml_mapping({
|
||||||
|
autoplay: {type: Bool, default: false},
|
||||||
|
captions: {type: Array(String), default: ["", "", ""], converter: StringToArray},
|
||||||
|
comments: {type: Array(String), default: ["youtube", ""], converter: StringToArray},
|
||||||
|
continue: {type: Bool, default: false},
|
||||||
|
dark_mode: {type: Bool, default: false},
|
||||||
|
latest_only: {type: Bool, default: false},
|
||||||
|
listen: {type: Bool, default: false},
|
||||||
|
local: {type: Bool, default: false},
|
||||||
|
locale: {type: String, default: "en-US"},
|
||||||
|
max_results: {type: Int32, default: 40},
|
||||||
|
notifications_only: {type: Bool, default: false},
|
||||||
|
quality: {type: String, default: "hd720"},
|
||||||
|
redirect_feed: {type: Bool, default: false},
|
||||||
|
related_videos: {type: Bool, default: true},
|
||||||
|
sort: {type: String, default: "published"},
|
||||||
|
speed: {type: Float32, default: 1.0_f32},
|
||||||
|
thin_mode: {type: Bool, default: false},
|
||||||
|
unseen_only: {type: Bool, default: false},
|
||||||
|
video_loop: {type: Bool, default: false},
|
||||||
|
volume: {type: Int32, default: 100},
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
struct Config
|
struct Config
|
||||||
|
module ConfigPreferencesConverter
|
||||||
|
def self.from_yaml(ctx : YAML::ParseContext, node : YAML::Nodes::Node) : Preferences
|
||||||
|
Preferences.new(*ConfigPreferences.new(ctx, node).to_tuple)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.to_yaml(value : Preferences, yaml : YAML::Nodes::Builder)
|
||||||
|
value.to_yaml(yaml)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
YAML.mapping({
|
YAML.mapping({
|
||||||
channel_threads: Int32, # Number of threads to use for crawling videos from channels (for updating subscriptions)
|
channel_threads: Int32, # Number of threads to use for crawling videos from channels (for updating subscriptions)
|
||||||
feed_threads: Int32, # Number of threads to use for updating feeds
|
feed_threads: Int32, # Number of threads to use for updating feeds
|
||||||
@ -22,7 +94,11 @@ user: String,
|
|||||||
registration_enabled: {type: Bool, default: true},
|
registration_enabled: {type: Bool, default: true},
|
||||||
statistics_enabled: {type: Bool, default: false},
|
statistics_enabled: {type: Bool, default: false},
|
||||||
admins: {type: Array(String), default: [] of String},
|
admins: {type: Array(String), default: [] of String},
|
||||||
external_port: {type: Int32 | Nil, default: nil},
|
external_port: {type: Int32?, default: nil},
|
||||||
|
default_user_preferences: {type: Preferences,
|
||||||
|
default: Preferences.new(*ConfigPreferences.from_yaml("").to_tuple),
|
||||||
|
converter: ConfigPreferencesConverter,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
macro add_mapping(mapping)
|
macro db_mapping(mapping)
|
||||||
def initialize({{*mapping.keys.map { |id| "@#{id}".id }}})
|
def initialize({{*mapping.keys.map { |id| "@#{id}".id }}})
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -18,6 +18,22 @@ macro json_mapping(mapping)
|
|||||||
end
|
end
|
||||||
|
|
||||||
JSON.mapping({{mapping}})
|
JSON.mapping({{mapping}})
|
||||||
|
YAML.mapping({{mapping}})
|
||||||
|
end
|
||||||
|
|
||||||
|
macro yaml_mapping(mapping)
|
||||||
|
def initialize({{*mapping.keys.map { |id| "@#{id}".id }}})
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_a
|
||||||
|
return [{{*mapping.keys.map { |id| "@#{id}".id }}}]
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_tuple
|
||||||
|
return { {{*mapping.keys.map { |id| "@#{id}".id }}} }
|
||||||
|
end
|
||||||
|
|
||||||
|
YAML.mapping({{mapping}})
|
||||||
end
|
end
|
||||||
|
|
||||||
macro templated(filename, template = "template")
|
macro templated(filename, template = "template")
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
struct MixVideo
|
struct MixVideo
|
||||||
add_mapping({
|
db_mapping({
|
||||||
title: String,
|
title: String,
|
||||||
id: String,
|
id: String,
|
||||||
author: String,
|
author: String,
|
||||||
@ -11,7 +11,7 @@ struct MixVideo
|
|||||||
end
|
end
|
||||||
|
|
||||||
struct Mix
|
struct Mix
|
||||||
add_mapping({
|
db_mapping({
|
||||||
title: String,
|
title: String,
|
||||||
id: String,
|
id: String,
|
||||||
videos: Array(MixVideo),
|
videos: Array(MixVideo),
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
struct PlaylistVideo
|
struct PlaylistVideo
|
||||||
add_mapping({
|
db_mapping({
|
||||||
title: String,
|
title: String,
|
||||||
id: String,
|
id: String,
|
||||||
author: String,
|
author: String,
|
||||||
@ -13,7 +13,7 @@ struct PlaylistVideo
|
|||||||
end
|
end
|
||||||
|
|
||||||
struct Playlist
|
struct Playlist
|
||||||
add_mapping({
|
db_mapping({
|
||||||
title: String,
|
title: String,
|
||||||
id: String,
|
id: String,
|
||||||
author: String,
|
author: String,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
struct SearchVideo
|
struct SearchVideo
|
||||||
add_mapping({
|
db_mapping({
|
||||||
title: String,
|
title: String,
|
||||||
id: String,
|
id: String,
|
||||||
author: String,
|
author: String,
|
||||||
@ -17,7 +17,7 @@ struct SearchVideo
|
|||||||
end
|
end
|
||||||
|
|
||||||
struct SearchPlaylistVideo
|
struct SearchPlaylistVideo
|
||||||
add_mapping({
|
db_mapping({
|
||||||
title: String,
|
title: String,
|
||||||
id: String,
|
id: String,
|
||||||
length_seconds: Int32,
|
length_seconds: Int32,
|
||||||
@ -25,7 +25,7 @@ struct SearchPlaylistVideo
|
|||||||
end
|
end
|
||||||
|
|
||||||
struct SearchPlaylist
|
struct SearchPlaylist
|
||||||
add_mapping({
|
db_mapping({
|
||||||
title: String,
|
title: String,
|
||||||
id: String,
|
id: String,
|
||||||
author: String,
|
author: String,
|
||||||
@ -37,7 +37,7 @@ struct SearchPlaylist
|
|||||||
end
|
end
|
||||||
|
|
||||||
struct SearchChannel
|
struct SearchChannel
|
||||||
add_mapping({
|
db_mapping({
|
||||||
author: String,
|
author: String,
|
||||||
ucid: String,
|
ucid: String,
|
||||||
author_thumbnail: String,
|
author_thumbnail: String,
|
||||||
|
@ -11,7 +11,7 @@ struct User
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
add_mapping({
|
db_mapping({
|
||||||
updated: Time,
|
updated: Time,
|
||||||
notifications: Array(String),
|
notifications: Array(String),
|
||||||
subscriptions: Array(String),
|
subscriptions: Array(String),
|
||||||
@ -26,29 +26,6 @@ struct User
|
|||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
DEFAULT_USER_PREFERENCES = Preferences.new(
|
|
||||||
video_loop: false,
|
|
||||||
autoplay: false,
|
|
||||||
continue: false,
|
|
||||||
local: false,
|
|
||||||
listen: false,
|
|
||||||
speed: 1.0_f32,
|
|
||||||
quality: "hd720",
|
|
||||||
volume: 100,
|
|
||||||
comments: ["youtube", ""],
|
|
||||||
captions: ["", "", ""],
|
|
||||||
related_videos: true,
|
|
||||||
redirect_feed: false,
|
|
||||||
locale: "en-US",
|
|
||||||
dark_mode: false,
|
|
||||||
thin_mode: false,
|
|
||||||
max_results: 40,
|
|
||||||
sort: "published",
|
|
||||||
latest_only: false,
|
|
||||||
unseen_only: false,
|
|
||||||
notifications_only: false,
|
|
||||||
)
|
|
||||||
|
|
||||||
struct Preferences
|
struct Preferences
|
||||||
module StringToArray
|
module StringToArray
|
||||||
def self.to_json(value : Array(String), json : JSON::Builder)
|
def self.to_json(value : Array(String), json : JSON::Builder)
|
||||||
@ -71,29 +48,62 @@ struct Preferences
|
|||||||
|
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.to_yaml(value : Array(String), yaml : YAML::Nodes::Builder)
|
||||||
|
yaml.sequence do
|
||||||
|
value.each do |element|
|
||||||
|
yaml.scalar element
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.from_yaml(ctx : YAML::ParseContext, node : YAML::Nodes::Node) : Array(String)
|
||||||
|
begin
|
||||||
|
unless node.is_a?(YAML::Nodes::Sequence)
|
||||||
|
node.raise "Expected sequence, not #{node.class}"
|
||||||
|
end
|
||||||
|
|
||||||
|
result = [] of String
|
||||||
|
node.nodes.each do
|
||||||
|
unless node.is_a?(YAML::Nodes::Scalar)
|
||||||
|
node.raise "Expected scalar, not #{node.class}"
|
||||||
|
end
|
||||||
|
|
||||||
|
result << node.value
|
||||||
|
end
|
||||||
|
rescue ex
|
||||||
|
if node.is_a?(YAML::Nodes::Scalar)
|
||||||
|
result = [node.value, ""]
|
||||||
|
else
|
||||||
|
result = ["", ""]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
json_mapping({
|
json_mapping({
|
||||||
video_loop: {type: Bool, default: DEFAULT_USER_PREFERENCES.video_loop},
|
autoplay: {type: Bool, default: CONFIG.default_user_preferences.autoplay},
|
||||||
autoplay: {type: Bool, default: DEFAULT_USER_PREFERENCES.autoplay},
|
captions: {type: Array(String), default: CONFIG.default_user_preferences.captions, converter: StringToArray},
|
||||||
continue: {type: Bool, default: DEFAULT_USER_PREFERENCES.continue},
|
comments: {type: Array(String), default: CONFIG.default_user_preferences.comments, converter: StringToArray},
|
||||||
local: {type: Bool, default: DEFAULT_USER_PREFERENCES.local},
|
continue: {type: Bool, default: CONFIG.default_user_preferences.continue},
|
||||||
listen: {type: Bool, default: DEFAULT_USER_PREFERENCES.listen},
|
dark_mode: {type: Bool, default: CONFIG.default_user_preferences.dark_mode},
|
||||||
speed: {type: Float32, default: DEFAULT_USER_PREFERENCES.speed},
|
latest_only: {type: Bool, default: CONFIG.default_user_preferences.latest_only},
|
||||||
quality: {type: String, default: DEFAULT_USER_PREFERENCES.quality},
|
listen: {type: Bool, default: CONFIG.default_user_preferences.listen},
|
||||||
volume: {type: Int32, default: DEFAULT_USER_PREFERENCES.volume},
|
local: {type: Bool, default: CONFIG.default_user_preferences.local},
|
||||||
comments: {type: Array(String), default: DEFAULT_USER_PREFERENCES.comments, converter: StringToArray},
|
locale: {type: String, default: CONFIG.default_user_preferences.locale},
|
||||||
captions: {type: Array(String), default: DEFAULT_USER_PREFERENCES.captions, converter: StringToArray},
|
max_results: {type: Int32, default: CONFIG.default_user_preferences.max_results},
|
||||||
redirect_feed: {type: Bool, default: DEFAULT_USER_PREFERENCES.redirect_feed},
|
notifications_only: {type: Bool, default: CONFIG.default_user_preferences.notifications_only},
|
||||||
related_videos: {type: Bool, default: DEFAULT_USER_PREFERENCES.related_videos},
|
quality: {type: String, default: CONFIG.default_user_preferences.quality},
|
||||||
dark_mode: {type: Bool, default: DEFAULT_USER_PREFERENCES.dark_mode},
|
redirect_feed: {type: Bool, default: CONFIG.default_user_preferences.redirect_feed},
|
||||||
thin_mode: {type: Bool, default: DEFAULT_USER_PREFERENCES.thin_mode},
|
related_videos: {type: Bool, default: CONFIG.default_user_preferences.related_videos},
|
||||||
max_results: {type: Int32, default: DEFAULT_USER_PREFERENCES.max_results},
|
sort: {type: String, default: CONFIG.default_user_preferences.sort},
|
||||||
sort: {type: String, default: DEFAULT_USER_PREFERENCES.sort},
|
speed: {type: Float32, default: CONFIG.default_user_preferences.speed},
|
||||||
latest_only: {type: Bool, default: DEFAULT_USER_PREFERENCES.latest_only},
|
thin_mode: {type: Bool, default: CONFIG.default_user_preferences.thin_mode},
|
||||||
unseen_only: {type: Bool, default: DEFAULT_USER_PREFERENCES.unseen_only},
|
unseen_only: {type: Bool, default: CONFIG.default_user_preferences.unseen_only},
|
||||||
notifications_only: {type: Bool, default: DEFAULT_USER_PREFERENCES.notifications_only},
|
video_loop: {type: Bool, default: CONFIG.default_user_preferences.video_loop},
|
||||||
locale: {type: String, default: DEFAULT_USER_PREFERENCES.locale},
|
volume: {type: Int32, default: CONFIG.default_user_preferences.volume},
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -174,7 +184,7 @@ def fetch_user(sid, headers, db)
|
|||||||
|
|
||||||
token = Base64.urlsafe_encode(Random::Secure.random_bytes(32))
|
token = Base64.urlsafe_encode(Random::Secure.random_bytes(32))
|
||||||
|
|
||||||
user = User.new(Time.now, [] of String, channels, email, DEFAULT_USER_PREFERENCES, nil, token, [] of String)
|
user = User.new(Time.now, [] of String, channels, email, CONFIG.default_user_preferences, nil, token, [] of String)
|
||||||
return user, sid
|
return user, sid
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -182,7 +192,7 @@ def create_user(sid, email, password)
|
|||||||
password = Crypto::Bcrypt::Password.create(password, cost: 10)
|
password = Crypto::Bcrypt::Password.create(password, cost: 10)
|
||||||
token = Base64.urlsafe_encode(Random::Secure.random_bytes(32))
|
token = Base64.urlsafe_encode(Random::Secure.random_bytes(32))
|
||||||
|
|
||||||
user = User.new(Time.now, [] of String, [] of String, email, DEFAULT_USER_PREFERENCES, password.to_s, token, [] of String)
|
user = User.new(Time.now, [] of String, [] of String, email, CONFIG.default_user_preferences, password.to_s, token, [] of String)
|
||||||
|
|
||||||
return user, sid
|
return user, sid
|
||||||
end
|
end
|
||||||
|
@ -521,7 +521,7 @@ struct Video
|
|||||||
return self.info["length_seconds"].to_i
|
return self.info["length_seconds"].to_i
|
||||||
end
|
end
|
||||||
|
|
||||||
add_mapping({
|
db_mapping({
|
||||||
id: String,
|
id: String,
|
||||||
info: {
|
info: {
|
||||||
type: HTTP::Params,
|
type: HTTP::Params,
|
||||||
@ -818,16 +818,16 @@ def process_video_params(query, preferences)
|
|||||||
volume ||= preferences.volume
|
volume ||= preferences.volume
|
||||||
end
|
end
|
||||||
|
|
||||||
autoplay ||= DEFAULT_USER_PREFERENCES.autoplay.to_unsafe
|
autoplay ||= CONFIG.default_user_preferences.autoplay.to_unsafe
|
||||||
continue ||= DEFAULT_USER_PREFERENCES.continue.to_unsafe
|
continue ||= CONFIG.default_user_preferences.continue.to_unsafe
|
||||||
listen ||= DEFAULT_USER_PREFERENCES.listen.to_unsafe
|
listen ||= CONFIG.default_user_preferences.listen.to_unsafe
|
||||||
local ||= DEFAULT_USER_PREFERENCES.local.to_unsafe
|
local ||= CONFIG.default_user_preferences.local.to_unsafe
|
||||||
preferred_captions ||= DEFAULT_USER_PREFERENCES.captions
|
preferred_captions ||= CONFIG.default_user_preferences.captions
|
||||||
quality ||= DEFAULT_USER_PREFERENCES.quality
|
quality ||= CONFIG.default_user_preferences.quality
|
||||||
related_videos ||= DEFAULT_USER_PREFERENCES.related_videos.to_unsafe
|
related_videos ||= CONFIG.default_user_preferences.related_videos.to_unsafe
|
||||||
speed ||= DEFAULT_USER_PREFERENCES.speed
|
speed ||= CONFIG.default_user_preferences.speed
|
||||||
video_loop ||= DEFAULT_USER_PREFERENCES.video_loop.to_unsafe
|
video_loop ||= CONFIG.default_user_preferences.video_loop.to_unsafe
|
||||||
volume ||= DEFAULT_USER_PREFERENCES.volume
|
volume ||= CONFIG.default_user_preferences.volume
|
||||||
|
|
||||||
autoplay = autoplay == 1
|
autoplay = autoplay == 1
|
||||||
continue = continue == 1
|
continue = continue == 1
|
||||||
|
Loading…
Reference in New Issue
Block a user