Skip to content

Instantly share code, notes, and snippets.

@stuxcrystal
Last active January 17, 2017 22:47
Show Gist options
  • Save stuxcrystal/3c4cdeee5b8eaba3552e0dbefdd11dcb to your computer and use it in GitHub Desktop.
Save stuxcrystal/3c4cdeee5b8eaba3552e0dbefdd11dcb to your computer and use it in GitHub Desktop.
Adds Vapoursynth to MetaPath
import vsimport
from ffms2 import Source
clip = Source("/path/to/your/clip.mkv")
clip.set_output()
"""
VSImport. Supercharge your VapourSynth-Code
VSImport lets you import VapourSynth-Namespaces as if they were normal python modules.
To enable this feature just use:
>>> import vsimport
As soon as you did that, any vapoursynth-namespace can be imported into your module.
>>> from std import AssumeFPS, BlankClip
>>> c = BlankClip(length=240)
>>> c = AssumeFPS(c, fpsnum=60)
>>> c.set_output()
It even work on *-imports
>>> from std import *
>>> BlankClip(length=240) # doctest: +ELLIPSIS
<vapoursynth.VideoNode object at 0x...>
If a normal python-module already shadowed the namespace,
you can use the virtual 'vpy'-package to import your namespaces.
>>> from vpy.std import BlankClip
>>> BlankClip(length=240).set_output()
The vpy-package itself exposes a variable containing the current core.
>>> import vpy
>>> vpy.core # doctest: +ELLIPSIS
<vapoursynth.Core object at ...>
It also lists all plugins.
>>> vpy.plugins # doctest: +ELLIPSIS
[...]
Internal Notes:
The core-singleton will be created with the first import.
Create the core before you import this module for custom settings.
>>> import vapoursynth
>>> vapoursynth.get_core() # doctest: +SKIP
<vapoursynth.Core object at ...>
>>> import vsimport
>>> from vpy import core
>>> core # doctest: +ELLIPSIS
<vapoursynth.Core object at ...>
Additinally, some software only create a single python interpreter
for multiple passes thus creating multiple vapoursynth-cores. All
filters are deferred so that we always use the current core.
To access the deferred filter directly the filter-attribute will
contain the current filter.
>>> from std import AssumeFPS
>>> AssumeFPS
<DeferredFilter std.AssumeFPS>
>>> AssumeFPS.filter # doctest: +ELLIPSIS
<vapoursynth.Function object at ...>
"""
import sys
import functools
from types import ModuleType
from importlib.abc import Loader, Finder
import vapoursynth
class DeferredFilter(ModuleType):
def __init__(self, namespace, name):
self.namespace = namespace
self.name = name
@property
def filter(self):
"""Returns the current function object"""
return getattr(getattr(vapoursynth.get_core(), self.namespace), self.name)
def __call__(self, *args, **kwargs):
return self.filter(*args, **kwargs)
def __repr__(self):
return "<DeferredFilter %s.%s>" % (self.namespace, self.name)
class VapoursynthExtension(ModuleType):
@classmethod
def from_name(cls, name):
class FakeNS:
pass
fns = FakeNS()
fns.name = name
return cls(fns)
def __init__(self, spec):
super(VapoursynthExtension, self).__init__(spec.name)
self._name = spec.name
if self._name.startswith("vpy."):
self.__package__ = "vpy"
self._name = self._name[4:]
def __getattr__(self, name):
if name in self.get_functions():
return DeferredFilter(self._name, name)
return super(VapoursynthExtension, self).__getattr__(name)
@property
def __all__(self):
return list(self.get_functions())
def get_functions(self):
data = set()
for plugin in vapoursynth.get_core().get_plugins().values():
if plugin['namespace'] == self._name:
data |= set(plugin['functions'].keys())
return data
class VpyModule(ModuleType):
def __init__(self, spec):
super(VpyModule, self).__init__(spec.name)
self.DeferredFilter = DeferredFilter
@property
def __all__(self):
return self.plugins + ['core', 'DeferredFilter']
@property
def core(self):
"""Returns the current core of this environment"""
return vapoursynth.get_core()
@property
def plugins(self):
"""Returns the plugins in this environment."""
return list(importer.namespaces)
def __getattr__(self, name):
if name in self.plugins:
return VapoursynthExtension.from_name(name)
return super(VpyModule, self).__getattr__(name)
class CoreModuleLoader(Loader):
"""
Loads vapoursynth-extensions as modules.
"""
def create_module(self, spec):
if spec.name == "vpy":
module = VpyModule(spec)
module.__package__ = "vpy"
module.__path__ = None
return module
return VapoursynthExtension(spec)
def exec_module(self, module):
pass
def module_repr(self, module):
return "<VapourSynthNamespace %s>"%(module._name)
class VapoursynthPluginImporter(Finder):
def __init__(self):
self.loader = CoreModuleLoader()
@property
def namespaces(self):
namespaces = set()
for plugin in vapoursynth.get_core().get_plugins().values():
namespaces.add(plugin['namespace'])
return namespaces
def find_module(self, fullname, path=None):
if fullname == "vpy":
return self.loader
if fullname.startswith("vpy."):
fullname = fullname[4:]
if fullname in self.namespaces:
return self.loader
return None
importer = VapoursynthPluginImporter()
sys.meta_path.append(importer)
if __name__ == "__main__":
import doctest
doctest.testmod()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment