|
|
# То же самое, но на julia
|
|
|
# Версия 1.0 (рабочая)
|
|
|
|
|
|
using Logging
|
|
|
using Printf
|
|
|
using Dates
|
|
|
using CRC32c
|
|
|
using JSON
|
|
|
using Base.Threads
|
|
|
using MySQL
|
|
|
# using DBInterface
|
|
|
|
|
|
# debuglogger = ConsoleLogger(stderr, Logging.Debug)
|
|
|
# global_logger(debuglogger)
|
|
|
|
|
|
# правильный перевод!
|
|
|
function humanbytes(B)
|
|
|
"""Return the given bytes as a human friendly KB, MB, GB, or TB string."""
|
|
|
B = float(B)
|
|
|
KB = float(1024)
|
|
|
MB = float(KB ^ 2) # 1,048,576
|
|
|
GB = float(KB ^ 3) # 1,073,741,824
|
|
|
TB = float(KB ^ 4) # 1,099,511,627,776
|
|
|
|
|
|
if B < KB
|
|
|
return @sprintf("%.2f Bytes", B)
|
|
|
elseif KB <= B && B < MB
|
|
|
return @sprintf("%.2f KB", (B / KB))
|
|
|
elseif MB <= B && B < GB
|
|
|
return @sprintf("%.2f MB", (B / MB))
|
|
|
elseif GB <= B && B < TB
|
|
|
return @sprintf("%.2f GB", (B / GB))
|
|
|
elseif TB <= B
|
|
|
return @sprintf("%.2f TB", (B / KB))
|
|
|
end
|
|
|
end
|
|
|
|
|
|
function humanbitrate(s)
|
|
|
"""
|
|
|
# The function "humanbitrate" takes a string representing a bitrate in the format "a/b" and returns
|
|
|
the bitrate as a float with one decimal place.
|
|
|
|
|
|
:param s: The parameter "s" is a string that represents a fraction in the format "a/b", where "a"
|
|
|
and "b" are numbers
|
|
|
:return: the bitrate as a string.
|
|
|
"""
|
|
|
items = split(s, "/")
|
|
|
a = parse(Float64, items[1])
|
|
|
b = parse(Float64, items[2])
|
|
|
bitrate = @sprintf("%8.1f", (a / b))
|
|
|
return strip(bitrate)
|
|
|
end
|
|
|
|
|
|
function new_name(name)
|
|
|
matches = Dict(
|
|
|
"Сек" => r"(.+) Сек.*",
|
|
|
"Сцен" => r"(.+) Сцен.*",
|
|
|
"Голые" => r"(.+) Голые.*",
|
|
|
"Откро" => r"(.+) Откро.*",
|
|
|
"Посте" => r"(.+) Посте.*",
|
|
|
"Изнас" => r"(.+) Изнас.*",
|
|
|
"Инцес" => r"(.+) Инцес.*",
|
|
|
"Лесб" => r"(.+) Лесб.*",
|
|
|
"Эро" => r"(.+) Эро.*"
|
|
|
)
|
|
|
for (k, v) in matches
|
|
|
if contains(name, k)
|
|
|
base, ext = splitext(name)
|
|
|
new_name = replace(base, v => s"\1")
|
|
|
# @debug base, new_name
|
|
|
return string(new_name, ext)
|
|
|
end
|
|
|
end
|
|
|
return name
|
|
|
end
|
|
|
|
|
|
function valid_file(filename)
|
|
|
valids = [".avi", ".mkv", ".mp4", ".webm", ".mpeg"]
|
|
|
_, ext = splitext(filename)
|
|
|
return ext in valids
|
|
|
end
|
|
|
|
|
|
function humandate(d)
|
|
|
return Dates.format(Dates.unix2datetime(d), "dd.mm.yyyy")
|
|
|
end
|
|
|
|
|
|
# file_info function returns information from file
|
|
|
function file_info(filename)
|
|
|
_, ext = splitext(filename)
|
|
|
info = stat(filename)
|
|
|
crc = CRC32c.crc32c(open(filename, "r"))
|
|
|
m = Dict(
|
|
|
"filename" => filename,
|
|
|
"size" => info.size,
|
|
|
"hsize" => humanbytes(info.size),
|
|
|
"mtime" => info.mtime,
|
|
|
"ctime" => info.ctime,
|
|
|
"hmtime" => humandate(info.mtime),
|
|
|
"hctime" => humandate(info.ctime),
|
|
|
"ext" => ext,
|
|
|
"crc"=> Int(crc),
|
|
|
)
|
|
|
return m
|
|
|
end
|
|
|
|
|
|
# возвращает индекс видео-потока
|
|
|
function get_video_stream(stream)
|
|
|
for i in eachindex(stream)
|
|
|
if stream[i]["codec_type"] == "video"
|
|
|
return i
|
|
|
end
|
|
|
end
|
|
|
return -1
|
|
|
end
|
|
|
|
|
|
# возвращает индекс аудио-потока, -1 при отсутствии
|
|
|
function get_audio_stream(stream)
|
|
|
for i in eachindex(stream)
|
|
|
if stream[i]["codec_type"] == "audio"
|
|
|
return i
|
|
|
end
|
|
|
end
|
|
|
return -1
|
|
|
end
|
|
|
|
|
|
# Потоки могут быть перепутаны, поэтму нужно сначала
|
|
|
# определить индекс видео-потока
|
|
|
function file_meta(filename)
|
|
|
cmd = `ffprobe -v quiet -print_format json -show_format -show_streams "$filename"`
|
|
|
data = read(cmd, String) |> JSON.parse
|
|
|
n = get_video_stream(data["streams"])
|
|
|
audio = get_audio_stream(data["streams"]) != -1
|
|
|
dur = parse(Float64, data["format"]["duration"])
|
|
|
hdur = Dates.unix2datetime(dur)
|
|
|
hduration = Dates.format((hdur), "HH:MM:SS")
|
|
|
|
|
|
res = Dict(
|
|
|
"duration" => hdur,
|
|
|
"hduration" => hduration,
|
|
|
"width" => data["streams"][n]["width"],
|
|
|
"height" => data["streams"][n]["height"],
|
|
|
"bit_rate" => humanbitrate(data["streams"][n]["avg_frame_rate"]),
|
|
|
"codec" => data["streams"][n]["codec_name"],
|
|
|
"audio" => audio,
|
|
|
"tags" => "",
|
|
|
"type" => hduration < "00:10:00" ? "clip" : "film",
|
|
|
"newname" => "",
|
|
|
"poster" => "",
|
|
|
# "aspect_ratio" => data["streams"][n]["display_aspect_ratio"],
|
|
|
)
|
|
|
return res
|
|
|
end
|
|
|
|
|
|
function check_file(filename)
|
|
|
# println(filename)
|
|
|
v2 = file_meta(filename)
|
|
|
v1 = file_info(filename)
|
|
|
result = merge!(v1, v2)
|
|
|
# println(info)
|
|
|
return result
|
|
|
end
|
|
|
|
|
|
function main(host_id::Integer)
|
|
|
dir = "d:\\vids\\ero\\2"
|
|
|
@info "Обработка каталога: $dir"
|
|
|
|
|
|
files = readdir(dir, join=true)
|
|
|
n = length(files)
|
|
|
println("всего: $n files")
|
|
|
|
|
|
conn = DBInterface.connect(MySQL.Connection, "xigmanas", "itman", "X753951x", db="vid")
|
|
|
@time begin
|
|
|
# @sync begin
|
|
|
for file in filter(valid_file, files)
|
|
|
# Threads.@spawn begin
|
|
|
meta = check_file(file)
|
|
|
meta["host_id"] = host_id
|
|
|
# println(meta)
|
|
|
save_db(conn, meta)
|
|
|
# end
|
|
|
end
|
|
|
# end
|
|
|
end
|
|
|
|
|
|
println("обработано")
|
|
|
close(conn)
|
|
|
end
|
|
|
|
|
|
function exist(conn, crc::Integer)
|
|
|
cmd = "select count(*) as cnt from filemeta where crc = $crc"
|
|
|
result = DBInterface.execute(conn, cmd)
|
|
|
data = first(result)
|
|
|
# println("data = $data")
|
|
|
return data.cnt > 0
|
|
|
end
|
|
|
|
|
|
# сохраняет meta в БД
|
|
|
function save_db(conn, m)
|
|
|
filename = m["filename"]
|
|
|
if exist(conn, m["crc"])
|
|
|
@info "уже имеется: $filename"
|
|
|
else
|
|
|
println("сохраняю: $filename")
|
|
|
host_id = m["host_id"]
|
|
|
filename = replace(m["filename"], "\\" => "\\\\")
|
|
|
newname = m["newname"]
|
|
|
size = m["size"]
|
|
|
hsize = m["hsize"]
|
|
|
hduration = m["hduration"]
|
|
|
width = m["width"]
|
|
|
height = m["height"]
|
|
|
bitrate = m["bit_rate"]
|
|
|
ext = m["ext"]
|
|
|
crc = m["crc"]
|
|
|
hctime = m["hctime"]
|
|
|
hmtime = m["hmtime"]
|
|
|
poster = m["poster"]
|
|
|
audio = m["audio"]
|
|
|
codec = m["codec"]
|
|
|
tags = m["tags"]
|
|
|
type = m["type"]
|
|
|
|
|
|
fields = """
|
|
|
host_id, filename, newname, size,
|
|
|
hsize, duration, width,
|
|
|
height, bitrate, ext, crc,
|
|
|
ctime, mtime,
|
|
|
poster, audio, codec, tags,
|
|
|
type
|
|
|
"""
|
|
|
values = """
|
|
|
$host_id, '$filename', '$newname', $size,
|
|
|
'$hsize', '$hduration', $width,
|
|
|
$height, '$bitrate', '$ext', $crc,
|
|
|
'$hctime', '$hmtime',
|
|
|
'$poster', $audio, '$codec', '$tags',
|
|
|
'$type'
|
|
|
"""
|
|
|
cmd = "insert into filemeta ($fields) values ($values)"
|
|
|
println("file: ", filename)
|
|
|
result = DBInterface.execute(conn, cmd)
|
|
|
# println("result: ", result)
|
|
|
end
|
|
|
end
|
|
|
|
|
|
function openDB()
|
|
|
conn = DBInterface.connect(MySQL.Connection, "xigmanas", "itman", "X753951x", db="sea")
|
|
|
limit = 2
|
|
|
ext = ".webp"
|
|
|
cmd = "select ext, newurl from filemeta where ext = '$ext' limit $limit"
|
|
|
result = DBInterface.execute(conn, cmd)
|
|
|
# println(typeof(result))
|
|
|
for s in result
|
|
|
println(s.ext, ' ', s.newurl)
|
|
|
end
|
|
|
end
|
|
|
|
|
|
#=
|
|
|
-------- основная программа --------------
|
|
|
=#
|
|
|
|
|
|
# parallel_execution()
|
|
|
# openDB()
|
|
|
main(1)
|