#!/usr/bin/env lua
local util = require 'lib.util'
local extract = function (name, patterns)
local r
for _, p in pairs(patterns) do
r = r or name:match(p)
name = name:gsub(p, '')
end
return name, r
end
local build_dlim = function (name, attrs)
local dlim ,r
attrs = attrs or {}
dlim = '[%-%.%s]?'
local vcodecs = {
'[M]m[Pp][Ee][Gg]' .. dlim .. '[1234]',
}
local acodecs = {
'[Dd][Tt][Ss]' .. dlim .. '[Hh][Dd]',
'[Dd][Dd]' .. dlim .. '[57]%.1',
}
local sources= {
"[Ww][Ee][Bb]" .. dlim .. "[Dd][Ll]",
"[Hh][Dd]" .. dlim .. "[Tt][Vv]",
"[Hh][Dd]" .. dlim .. "[Tt][Ss]",
}
local series = {
'[Ss]%d%d?' .. dlim .. '[Ee]%d%d?',
'[Ss]%d%d?' .. dlim .. '[Ee][Pp]' .. dlim .. '%d%d?',
'Season' .. dlim .. '%d%d?' .. dlim .. 'Episode' .. dlim .. '%d%d?'
}
local sizes = {
'%d%d%d' .. dlim .. '[Mm][Bb]',
'%d%d?%.%d%d?' .. dlim .. '[Gg][Bb]',
}
local depths = {
'1[02]' .. dlim .. '[Bb][Ii][Tt]'
}
name, attrs.vcodec = extract(name, vcodecs)
name, attrs.source = extract(name, sources)
name, attrs.acodecs = extract(name, acodecs)
name, attrs.size = extract(name, sizes)
name, attrs.depth = extract(name, depths)
name, r = extract(name, series)
if r then
attrs.season = tonumber(r:match('%d+'))
attrs.episode = tonumber(r:match('%d+$'))
end
return name, attrs
end
local build_atom = function (name, attrs)
local r, year
attrs = attrs or {}
local vcodecs = {
"[Aa][Vv]1",
"[xXHh]26[345]",
"[Aa][Vv][Cc]",
"[Hh][Ee][Vv][Cc]",
"[Xx][Vv][Ii][Dd]",
}
local acodecs = {
"[Oo][Pp][Uu][Ss]",
"[Aa][Aa][Cc]",
"[Ee]?[Aa][Cc]3",
"[Dd][Tt][Ss]",
}
local sources= {
"[Bb][Ll][Uu][Rr][Aa][Yy]",
"[Bb][Rr][Rr][Ii][Pp]",
"[Dd][Vv][Dd][Rr][Ii][Pp]",
"[Ww][Ee][Bb][Rr][Ii][Pp]",
"[Hh][Dd][Rr][Ii][Pp]",
"[Rr][Ee][Rr][Ii][Pp]",
}
local reses = {
"2160[Pp]",
"1440[Pp]",
"1080[Pp]",
"720[Pp]",
"480[Pp]",
"[Uu][Hh][Dd]",
"4[Kk]"
}
local series = {
'%d%d[Xx]%d%d',
}
local channels = {
'6[Cc][Hh]',
'[57]%.1',
}
name, attrs.vcodec = extract(name, vcodecs)
name, attrs.source = extract(name, sources)
name, attrs.res = extract(name, reses)
name, attrs.acodecs = extract(name, acodecs)
name, attrs.channel = extract(name, channels)
name, r = extract(name, series)
if r then
attrs.season = tonumber(r:match('%d+'))
attrs.episode = tonumber(r:match('%d+$'))
end
for y in name:gmatch('%d%d%d%d') do
year = tonumber(y)
if year > 1900 and year <= tonumber(os.date('%Y')) then
attrs.year = y
end
end
if attrs.year then
name = name:gsub(tostring(attrs.year), '')
end
return name, attrs
end
local build_low = function (name, attrs)
local low_attr, lows
lows = { 'SDH' }
low_attr = {}
for _, low in pairs(lows) do
low_attr[#low_attr + 1] = name:match(low)
name = name:gsub(low, '')
end
attrs = attrs or {}
if #low_attr > 0 then
attrs.low = low_attr
end
return name, attrs
end
local build_title = function (name, attrs)
attrs.title = {}
for w in name:gmatch('%w+') do
attrs.title[#attrs.title + 1] = w
end
if #attrs.title > 1 then
attrs.scene = attrs.title[#attrs.title]
attrs.title[#attrs.title] = nil
end
return attrs
end
local build = function (name)
local attrs = {}
name = build_dlim(name, attrs)
name = build_atom(name, attrs)
name = build_low(name, attrs)
build_title(name, attrs)
return attrs
end
local weigh = function (a1, a2)
local key_score, score
key_score = {
season = 15,
episode = 15,
title = 10,
source = 7,
scene = 5,
vcodec = 3,
acodec = 3,
rese = 2,
default = 1,
}
score = 0
for k, v in pairs(a1) do
if not a2[k] or k == 'episode' then
goto continue
end
if k == 'title' then
for _, title in pairs(v) do
if util.array_search(a2.title, title) then
score = score + key_score.title
end
end
elseif k == 'season' then
if a1.season == a2.season and a1.episode == a2.episode then
score = score + key_score.season + key_score.episode
end
else
if v == a2[k] then
score = score + (key_score[k] or key_score.default)
end
end
::continue::
end
return score
end
local fuzzy = function (name, tab)
local name_attr, high, score
high = {
score = 0,
name = next(tab)
}
name_attr = build(name)
for k in pairs(tab) do
score = weigh(name_attr, build(k))
if score > high.score then
high.score = score
high.name = k
end
end
return tab[high.name]
end
return {
build = build,
fuzzy = fuzzy,
}