Jump to content

ფილმები MAC OS-ზე 60 FPS-ში


მათე

Recommended Posts

მოგესალმებით. დღეს გასწავლით თუ როგორ უნდა მივიღოთ MAC-ზე ის საოცარი ეფექტი რომელსაც მაღალსიხშირიანი 600 800 hz-იანი ტელევიზორები იძლევიან. (სინამდვილეში 240-იანზე მეტი არცერთი არაა მარა მაინც :D ) 

windows-ში არის პროგრამა SVP free ვერსია. ნაწილობრივ შეზღუდულია, თუმცა საქმეს აკეთებს, ხოლო ამ პროგრამის MAC OS X და LINUX ვერსიები არის ფასიანი. თანაც ის ხერხი რომელსაც ახლა აგიხსნით საკმაოდ კარგ შედეგს მოგცემთ. ადრე windows როცა მეყენა ვხმარობდი SVP-ს და იმ მომენტში რა ეფექტიც იმას ქონდა იმაზე გაცილებით კარგად მუშაობს ეს ეხლა რაც გავაკეთე  ჩემს ჰაკინტოშზე. 

პირველ რიგში უნდა დააყენოთ ეს პროგრამები homebrew-ს დახმარებით. თვითონ homebrew-ს დაყენებას აქ არ ავხსნი აქ ნახავთ როგორ დააყენოთ homebrew el capitan-ზე https://coolestguidesontheplanet.com/installing-homebrew-on-os-x-el-capitan-10-11-package-manager-for-unix-apps/

სხვა MAC OS X-ზეც ნახავთ იოლად დაყენების გზას.

შემდეგ აყენებთ ამ პროგრამებს. ზოგს დაჭირდება 5-10-15 წუთამდეც, დაელოდეთ!

brew tap mpv-player/mpv
brew install --with-x265 --with-theora --with-rtmpdump --with-openssl --with-libvorbis --with-libass --with-libbs2b ffmpeg
brew install --without-harfbuzz libass
brew install --with-vapoursynth --with-bundle mpv
brew install mvtools
brew install ffms2
brew install subliminal
brew linkapps mpv

შემდეგ home დირექტორიაში ქმნით ფოლდერს .config . ნიშნავს რომ ის არის დამალული.
მის შიგნით კი ქმნით ფოლდერებს და ფაილებს, როგორც ეს სურათზეა აღნიშნული.

2726211ab837.jpg

აუცილებლად წაიკითხეთ კომენტარები კონფიგურაციის ფაილებში!

input.conf
 

Spoiler



# MPV-ს კონფიგურაცია    

# for mpv v0.16.0 or newer with vapoursynth and mvtools (last change, 5 April 2016)

#

# Input settings live in ~/.config/mpv/input.conf

# 

# აუქმებს trackpad-ს ჟესტებს, დაკლიკება მუშაობს.

 

AXIS_UP    ignore

AXIS_DOWN  ignore

AXIS_LEFT  ignore

AXIS_RIGHT ignore



# f-ზე დაჭერისას ან ვიდეოზე ორჯერ დაკლიკვისას fulscreen-ზე გადასვლის გაუქმება 



# f ignore

# MOUSE_BTN0_DBL ignore



# vapoursynth-ს სკრიპტის გაშვება shift + p



P vf toggle vapoursynth=~/.config/mpv/vapoursynth/interpolation.py



# bs2b-ს ჩართვა/გამორთვა, ხმას აქცევს binaural-დ,, რომელიც აუმჯობესებს ნაუშნიკებში ხმას. ffmpeg უნდა იყოს დაყენებული ამ არგუმენტით --with-libbs2b.



H af toggle lavfi=[bs2b=profile=jmeier]

 

osc.conf

Spoiler



# On screen control settings live in ~/.config/mpv/lua-settings/osc.conf

# valign ხაზი წევს OSC-ს ეკრანის ზედა ნაწილში რათა ხელი არ შეუშალოს საბთაითლებს.

# გადახედეთ მანუალს დამატებითი layout-სა და seekbar-ს სტილისთვის.

# გამოყენებულია მინიმალისტური სტილი.



layout=slimbox

valign=-1

boxalpha=160

hidetimeout=1000

seekbarstyle=bar

 

mpv.conf აქ ეკრანის გარჩევადობაც ჩაასწორეთ რაც თქვენ გაქვთ იმით
 

Spoiler



# MPV Settings

#

# Video

# highest quality სეთინგები არის საუკეთესო თუმცა მოითხოვს ძლიერ

# CPU-ს ამიტომ გამოიყენეთ  high ან medium სეთინგები. Highest quality

# გაქაჩავდა hardware acceleration რომ მუშაობდეს, მაგრამ ის არ მუშაობს ყველა ფორმატთან



# ცალკეა დანასტროიკებული 60 fps playback vapoursynth-სთან ერთად.. თუ გინდათ გამოიყენოთ 

# vapoursynth, გააუქმეთ ყველა სხვა და გაააქტიურეთ დაბლითა ერთი. high-სა დაmedium-ს შორის განსხვავებაა debanding.



# თუ გსურთ გამოიყენოთe vapoursynth სხვა ნასტროიკებთან ერთად უნდა გააუქმოთ

# hwdec და მოაშოროთ interpolation. debanding-ს მოშორებაც შესაძლოა დაგჭირდეთ.



# Non-vapoursynth, highest quality სეთინგია დეფოლტი. 

# თუ პრობლემა გაქვთ ჩამოაქვეითეთ სეთინგები ნელ-ნელა.



video-sync=display-resample



# Vapoursynth high quality preset



#vo=opengl:scale=spline36:cscale=spline36:dscale=mitchell:dither-depth=auto:correct-downscaling:sigmoid-upscaling:icc-profile-auto:es=no:deband

#hwdec=no



# Vapoursynth medium quality preset



#vo=opengl:scale=spline36:cscale=spline36:dscale=mitchell:dither-depth=auto:correct-downscaling:sigmoid-upscaling:icc-profile-auto:es=no

#hwdec=no



# Highest quality preset



vo=opengl:scale=ewa_lanczossharp:cscale=ewa_lanczossharp:scale-antiring=0.8:dscale=mitchell:dither-depth=auto:correct-downscaling:sigmoid-upscaling:icc-profile-auto:deband:blend-subtitles:tscale-clamp:interpolation:es=no

hwdec=videotoolbox



# High quality preset



# vo=opengl:scale=spline36:cscale=spline36:scale-antiring=0.6:dscale=mitchell:dither-depth=auto:correct-downscaling:sigmoid-upscaling:icc-profile-auto:deband:blend-subtitles:tscale-clamp:interpolation:es=no

# hwdec=videotoolbox



# Medium quality preset



# vo=opengl:scale=spline36:cscale=spline36:dscale=mitchell:dither-depth=auto:correct-downscaling:sigmoid-upscaling:blend-subtitles:tscale-clamp:interpolation

# hwdec=videotoolbox



# ესაა low quality სეთინგები, მაგრამ არ გირჩევთ ამის გამოყენებას.

# თუ გჭირდებათ ამის გამოყენება შეიძლება უკეთესი იყოს VLC-ს ან mplayerx-ს გამოყენება.

# Medium quality მაინც ჯობს ამათ ორივეს, მაგრამ არა low. 

# ერთადერთი სადაც შეილება ეს დაგჭირდეთ არის 1080p ვიდეოები და vapoursynth.



# vo=opengl:scale=bilinear

# hwdec=no



# Display

# To autofit-larger, you should write your screen resolution, if you don't know

# it, check here: http://www.whatismyscreenresolution.com

# Set fs line to *yes* if you want to start with mpv's non-native fullscreen. 

# Others are all easy to understand.



fs=no

force-window=yes

stop-screensaver

cursor-autohide=1000

autofit-larger=1366x768

osd-font='Helvetica Neue'



# Sound

# softvol controls mpv's volume settings, here it is disabled and left for

# OS X's mixer. Set audio channels as needed. This is fine for headphones.



softvol=no

audio-channels=2

ao=coreaudio:change-physical-format=yes



# Enable the line below to make Bauer stereo to binaural transformation default,

# which improves headphone listening of stereo audio records. ffmpeg must be installed

# with --with-libbs2b to use this.

#

# af=lavfi=[bs2b=profile=jmeier]



# Subtiles, with Crunchyroll defaults.



# I have choosen CR defaults since they are familiar 

# and everyone should have the typeface.



# sub-codepage is the subtitle encoding. Check the wiki page for your language 

# and change the second one: https://en.wikipedia.org/wiki/Windows_code_page#List



alang=jp,jpn

slang=en,enUS



sub-text-font='Trebuchet MS'

sub-text-border-size=1

sub-text-font-size=54

sub-text-margin-y=38



sub-codepage=utf8:cp1254



ass-vsfilter-aspect-compat=yes

 

scripts პაპკაში არის სულ 3 ფალი:

autoload.lua ეს გახსნილი ფაილის ფოლდერში არსებულ სხვა მედია ფაილებს ტვირთავს
autosub.lua  ეს იწერს საბთაითლებს. გამოჩენა გაქრობა v ღილაკით j-თ კი გადაცვლა ენების. b არის მოძებნა და გადმოწერა.
stats.lua ეს კი ვიდეოზე წერს ინფორმაციას მათ შორის FPS-ს და ბიტრეიტის. ღილაკი i ერთჯერადად გამოაჩენს, სულ თუ გინდათ არ აუშვათ ღილაკს ხელი.

autoload.lua

Spoiler



-- This script automatically loads playlist entries before and after the

-- the currently played file. It does so by scanning the directory a file is

-- located in when starting playback. It sorts the directory entries

-- alphabetically, and adds entries before and after the current file to

-- the internal playlist. (It stops if the it would add an already existing

-- playlist entry at the same position - this makes it "stable".)

-- Add at most 5000 * 2 files when starting a file (before + after).

MAXENTRIES = 5000



function Set (t)

    local set = {}

    for _, v in pairs(t) do set[v] = true end

    return set

end



EXTENSIONS = Set {

    'mkv', 'avi', 'mp4', 'ogv', 'webm', 'rmvb', 'flv', 'wmv', 'mpeg', 'mpg', 'm4v', '3gp',

    'wav', 'ogv', 'flac', 'm4a', 'wma',

}



mputils = require 'mp.utils'



function add_files_at(index, files)

    index = index - 1

    local oldcount = mp.get_property_number("playlist-count", 1)

    for i = 1, #files do

        mp.commandv("loadfile", files[i], "append")

        mp.commandv("playlist_move", oldcount + i - 1, index + i - 1)

    end

end



function get_extension(path)

    match = string.match(path, "%.([^%.]+)$" )

    if match == nil then

        return "nomatch"

    else

        return match

    end

end



table.filter = function(t, iter)

    for i = #t, 1, -1 do

        if not iter(t[i]) then

            table.remove(t, i)

        end

    end

end



function find_and_add_entries()

    local path = mp.get_property("path", "")

    local dir, filename = mputils.split_path(path)

    if #dir == 0 then

        return

    end

    local pl_count = mp.get_property_number("playlist-count", 1)

    if (pl_count > 1 and autoload == nil) or

       (pl_count == 1 and EXTENSIONS[string.lower(get_extension(filename))] == nil) then

        return

    else

        autoload = true

    end



    local files = mputils.readdir(dir, "files")

    if files == nil then

        return

    end

    table.filter(files, function (v, k)

        local ext = get_extension(v)

        if ext == nil then

            return false

        end

        return EXTENSIONS[string.lower(ext)]

    end)

    table.sort(files, function (a, b)

        local len = string.len(a) - string.len(b)

        if len ~= 0 then -- case for ordering filename ending with such as X.Y.Z

            local ext = string.len(get_extension(a)) + 1

            return string.sub(a, 1, -ext) < string.sub(b, 1, -ext)

        end

        return string.lower(a) < string.lower(b)

    end)



    if dir == "." then

        dir = ""

    end



    local pl = mp.get_property_native("playlist", {})

    local pl_current = mp.get_property_number("playlist-pos", 0) + 1

    -- Find the current pl entry (dir+"/"+filename) in the sorted dir list

    local current

    for i = 1, #files do

        if files[i] == filename then

            current = i

            break

        end

    end

    if current == nil then

        return

    end



    local append = {[-1] = {}, [1] = {}}

    for direction = -1, 1, 2 do -- 2 iterations, with direction = -1 and +1

        for i = 1, MAXENTRIES do

            local file = files[current + i * direction]

            local pl_e = pl[pl_current + i * direction]

            if file == nil or file[1] == "." then

                break

            end



            local filepath = dir .. file

            if pl_e then

                -- If there's a playlist entry, and it's the same file, stop.

                if pl_e.filename == filepath then

                    break

                end

            end



            if direction == -1 then

                if pl_current == 1 then -- never add additional entries in the middle

                    mp.msg.info("Prepending " .. file)

                    table.insert(append[-1], 1, filepath)

                end

            else

                mp.msg.info("Adding " .. file)

                table.insert(append[1], filepath)

            end

        end

    end



    add_files_at(pl_current + 1, append[1])

    add_files_at(pl_current, append[-1])

end



mp.register_event("start-file", find_and_add_entries)

 


autosub.lua
 

Spoiler



-- requires subliminal, version 1.0 or newer

-- default keybinding: b

local utils = require 'mp.utils'

function load_sub_fn()

    subl = "/usr/local/bin/subliminal" -- use 'which subliminal' to find the path

    mp.msg.info("Searching subtitle")

    mp.osd_message("Searching subtitle")

    t = {}

    t.args = {subl, "download", "-s", "-l", "en", mp.get_property("path")}

    res = utils.subprocess(t)

    if res.status == 0 then

        mp.commandv("rescan_external_files", "reselect") 

        mp.msg.info("Subtitle download succeeded")

        mp.osd_message("Subtitle download succeeded")

    else

        mp.msg.warn("Subtitle download failed")

        mp.osd_message("Subtitle download failed")

    end

end



mp.add_key_binding("b", "auto_load_subs", load_sub_fn)

 

stats.lua
 

Spoiler



-- Display some stats.

--

-- You can invoke the script with "i" by default or create a different key

-- binding in input.conf using "<yourkey> script_binding stats".

--

-- The style is configurable through a config file named "lua-settings/stats.conf"

-- located in your mpv directory.

--

-- Please note: not every property is always available and therefore not always

-- visible.



local options = require 'mp.options'



-- Options

local o = {

    ass_formatting = true,

    duration = 3,

    debug = false,



    -- Text style

    font = "Source Sans Pro",

    font_size = 11,

    font_color = "FFFFFF",

    border_size = 1.0,

    border_color = "262626",

    shadow_x_offset = 0.0,

    shadow_y_offset = 0.0,

    shadow_color = "000000",

    alpha = "11",



    -- Custom header for ASS tags to style the text output.

    -- Specifying this will ignore the text style values above and just

    -- use this string instead.

    custom_header = "",



    -- Text formatting

    -- With ASS

    nl = "\\N",

    indent = "\\h\\h\\h\\h\\h",

    prefix_sep = "\\h\\h",

    b1 = "{\\b1}",

    b0 = "{\\b0}",

    -- Without ASS

    no_ass_nl = "\n",

    no_ass_indent = "\t",

    no_ass_prefix_sep = " ",

    no_ass_b1 = "\027[1m",

    no_ass_b0 = "\027[0m",

}

options.read_options(o)





function main()

    local stats = {

        header = "",

        file = "",

        video = "",

        audio = ""

    }



    o.ass_formatting = o.ass_formatting and has_vo_window()

    if not o.ass_formatting then

        o.nl = o.no_ass_nl

        o.indent = o.no_ass_indent

        o.prefix_sep = o.no_ass_prefix_sep

        if not has_ansi() then

            o.b1 = ""

            o.b0 = ""

        else

            o.b1 = o.no_ass_b1

            o.b0 = o.no_ass_b0

        end

    end



    add_header(stats)

    add_file(stats)

    add_video(stats)

    add_audio(stats)



    mp.osd_message(join_stats(stats), o.duration)

end





function add_file(s)

    local sec = "file"

    s[sec] = ""



    append_property(s, sec, "filename", {prefix="File:", nl="", indent=""})

    append_property(s, sec, "metadata/title", {prefix="Title:"})

    append_property(s, sec, "chapter", {prefix="Chapter:"})

    if append_property(s, sec, "cache-used", {prefix="Cache:"}) then

        append_property(s, sec, "demuxer-cache-duration",

                        {prefix="+", suffix=" sec", nl="", indent=o.prefix_sep,

                         prefix_sep="", no_prefix_markup=true})

    end

end





function add_video(s)

    local sec = "video"

    s[sec] = ""

    if not has_video() then

        return

    end



    if append_property(s, sec, "video-codec", {prefix="Video:", nl="", indent=""}) then

        append_property(s, sec, "hwdec-active",

                        {prefix="(hwdec)", nl="", indent=" ",

                         no_prefix_markup=true, no_value=true},

                        {no=true})

    end

    append_property(s, sec, "avsync", {prefix="A-V:"})

    if append_property(s, sec, "drop-frame-count", {prefix="Dropped:"}) then

        append_property(s, sec, "vo-drop-frame-count", {prefix="VO:", nl=""})

        append_property(s, sec, "mistimed-frame-count", {prefix="Mistimed:", nl=""})

        append_property(s, sec, "vo-delayed-frame-count", {prefix="Delayed:", nl=""})

    end

    if append_property(s, sec, "display-fps", {prefix="Display FPS:", suffix=" (specified)"}) then

        append_property(s, sec, "estimated-display-fps",

                        {suffix=" (estimated)", nl="", indent=""})

    else

        append_property(s, sec, "estimated-display-fps",

                        {prefix="Display FPS:", suffix=" (estimated)"})

    end

    if append_property(s, sec, "fps", {prefix="FPS:", suffix=" (specified)"}) then

        append_property(s, sec, "estimated-vf-fps",

                        {suffix=" (estimated)", nl="", indent=""})

    else

        append_property(s, sec, "estimated-vf-fps",

                        {prefix="FPS:", suffix=" (estimated)"})

    end

    if append_property(s, sec, "video-speed-correction", {prefix="DS:"}) then

        append_property(s, sec, "audio-speed-correction",

                        {prefix="/", nl="", indent=" ", prefix_sep=" ", no_prefix_markup=true})

    end

    if append_property(s, sec, "video-params/w", {prefix="Native Resolution:"}) then

        append_property(s, sec, "video-params/h",

                        {prefix="x", nl="", indent=" ", prefix_sep=" ", no_prefix_markup=true})

    end

    append_property(s, sec, "window-scale", {prefix="Window Scale:"})

    append_property(s, sec, "video-params/aspect", {prefix="Aspect Ratio:"})

    append_property(s, sec, "video-params/pixelformat", {prefix="Pixel format:"})

    append_property(s, sec, "video-params/colormatrix", {prefix="Colormatrix:"})

    append_property(s, sec, "video-params/primaries", {prefix="Primaries:"})

    append_property(s, sec, "video-params/colorlevels", {prefix="Levels:"})

    append_property(s, sec, "packet-video-bitrate", {prefix="Bitrate:", suffix=" kbps"})

end





function add_audio(s)

    local sec = "audio"

    s[sec] = ""

    if not has_audio() then

        return

    end



    append_property(s, sec, "audio-codec", {prefix="Audio:", nl="", indent=""})

    append_property(s, sec, "audio-params/samplerate", {prefix="Sample Rate:", suffix=" Hz"})

    append_property(s, sec, "audio-params/channel-count", {prefix="Channels:"})

    append_property(s, sec, "packet-audio-bitrate", {prefix="Bitrate:", suffix=" kbps"})

end





function add_header(s)

    if not o.ass_formatting then

        s.header = ""

        return

    end

    if o.custom_header and o.custom_header ~= "" then

        s.header = set_ASS(true) .. o.custom_header

    else

        s.header = string.format("%s{\\fs%d}{\\fn%s}{\\bord%f}{\\3c&H%s&}{\\1c&H%s&}" ..

                                 "{\\alpha&H%s&}{\\xshad%f}{\\yshad%f}{\\4c&H%s&}",

                        set_ASS(true), o.font_size, o.font, o.border_size,

                        o.border_color, o.font_color, o.alpha, o.shadow_x_offset,

                        o.shadow_y_offset, o.shadow_color)

    end

end





-- Format and append a property.

-- A property whose value is either `nil` or empty (hereafter called "invalid")

-- is skipped and not appended.

-- Returns `false` in case nothing was appended, otherwise `true`.

--

-- s       : Table containing key `sec`.

-- sec     : Existing key in table `s`, value treated as a string.

-- property: The property to query and format (based on its OSD representation).

-- attr    : Optional table to overwrite certain (formatting) attributes for

--           this property.

-- exclude : Optional table containing keys which are considered invalid values

--           for this property. Specifying this will replace empty string as

--           default invalid value (nil is always invalid).

function append_property(s, sec, prop, attr, excluded)

    excluded = excluded or {[""] = true}

    local ret = mp.get_property_osd(prop)

    if not ret or excluded[ret] then

        if o.debug then

            print("No value for property: " .. prop)

        end

        return false

    end



    attr.prefix_sep = attr.prefix_sep or o.prefix_sep

    attr.indent = attr.indent or o.indent

    attr.nl = attr.nl or o.nl

    attr.suffix = attr.suffix or ""

    attr.prefix = attr.prefix or ""

    attr.no_prefix_markup = attr.no_prefix_markup or false

    attr.prefix = attr.no_prefix_markup and attr.prefix or b(attr.prefix)

    ret = attr.no_value and "" or ret



    s[sec] = string.format("%s%s%s%s%s%s%s", s[sec], attr.nl, attr.indent,

                           attr.prefix, attr.prefix_sep, no_ASS(ret), attr.suffix)

    return true

end





function no_ASS(t)

    return set_ASS(false) .. t .. set_ASS(true)

end





function set_ASS(b)

    if not o.ass_formatting then

        return ""

    end

    return mp.get_property_osd("osd-ass-cc/" .. (b and "0" or "1"))

end





function join_stats(s)

    r = s.header .. s.file



    if s.video and s.video ~= "" then

        r = r .. o.nl .. o.nl .. s.video

    end

    if s.audio and s.audio ~= "" then

        r = r .. o.nl .. o.nl .. s.audio

    end



    return r

end





function has_vo_window()

    return mp.get_property("vo-configured") == "yes"

end





function has_video()

    local r = mp.get_property("video")

    return r and r ~= "no" and r ~= ""

end





function has_audio()

    local r = mp.get_property("audio")

    return r and r ~= "no" and r ~= ""

end



function has_ansi()

    local is_windows = type(package) == 'table' and type(package.config) == 'string' and package.config:sub(1,1) == '\\'

    if is_windows then

        return os.getenv("ANSICON")

    end

    return true

end



function b(t)

    return o.b1 .. t .. o.b0

end



mp.add_key_binding("i", mp.get_script_name(), main, {repeatable=true})

 

და ყველაზე მთავარი interpolation.py
 

Spoiler



import vapoursynth as vs

core = vs.get_core()

core.std.LoadPlugin(path="/usr/local/lib/libmvtools.dylib")

core.std.LoadPlugin(path='/usr/local/lib/libffms2.dylib')



clip = video_in



src_num = int(float(container_fps) * 1e3)

src_den = int(1e3)

play_num = int(float(display_fps) * 1e3)

play_den = int(1e3)



if not (clip.width >= 1920 or clip.height >= 1080 or container_fps >= 60):

    clip = core.std.AssumeFPS(clip, fpsnum=src_num, fpsden=src_den)

    sup  = core.mv.Super(clip, pel=2, hpad=16, vpad=16)

    bvec = core.mv.Analyse(sup, truemotion=True, blksize=16, isb=True, chroma=True, search=3)

    fvec = core.mv.Analyse(sup, truemotion=True, blksize=16, isb=False, chroma=True, search=3)

    clip = core.mv.BlockFPS(clip, sup, bvec, fvec, num=play_num, den=play_den, mode=3, thscd2=48)



clip.set_output()



print("Source fps", (src_num/src_den))

print("Playback fps", (play_num/play_den))

 

არ დაგავიწყდეთ interpolation.py აქციოთ გამშვებად ბრძანებით chmod +x "სრული მისამართი ამ ფაილის"

და ასევე გაუშვით ბრძანება chown -R ~/.config

როცა გაუშვებთ ასეთ რამეს დაწერს კონსოლში

Opening video filter: [vapoursynth file=~/.config/mpv/vapoursynth/interpolation.py]
Source fps 25.0
Playback fps 59.862

გადაამოწმეთ ფაილები და ფოლდერები როგორც ზემოთ სურათში განახეთ!

ვიდეო გაუშვით ხოლმე ასე ტერმინალიდან mpv "ფაილის სრული მისამართი"

ან შეგიძლიათ მარჯვენა ღილაკი და open with mpv

f  ღილაკი ან ვიდეოზე ორჯერ დაკლიკება გადაიყვანს  fullscreen-ში. shift + p გაუშვებს interpolation.py სკრიპტს. დანარჩენი ღილაკები ზემოთ მაქვს დაწერილი. ისრებით გადახვევა/გადმოხვევა მუშაობს.

  • Upvote 2
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.