forked from pyload/pyload
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAddon.py
More file actions
203 lines (143 loc) · 5.55 KB
/
Addon.py
File metadata and controls
203 lines (143 loc) · 5.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# -*- coding: utf-8 -*-
#from functools import wraps
from pyload.utils import has_method, to_list
from Base import Base
def class_name(p):
return p.rpartition(".")[2]
def AddEventListener(event):
""" Used to register method for events. Arguments needs to match parameter of event
:param event: Name of event or list of them.
"""
class _klass(object):
def __new__(cls, f, *args, **kwargs):
for ev in to_list(event):
addonManager.addEventListener(class_name(f.__module__), f.func_name, ev)
return f
return _klass
def AddonHandler(label, desc, package=True, media=-1):
""" Register Handler for files, packages, or arbitrary callable methods. In case package is True (default)
The method should only accept a pid as argument. When media is set it will work on files
and should accept a fileid. Only when both is None the method can be arbitrary.
:param label: verbose name
:param desc: short description
:param package: True if method works withs packages
:param media: media type of the file to work with.
"""
class _klass(object):
def __new__(cls, f, *args, **kwargs):
addonManager.addAddonHandler(class_name(f.__module__), f.func_name, label, desc,
f.func_code.co_varnames[1:], package, media)
return f
return _klass
def AddonProperty(name, desc, default=None, fire_event=True):
""" Use this function to declare class variables, that will be exposed as :class:`AddonInfo`.
It works similar to the @property function. You declare the variable like `state = AddonProperty(...)`
and use it as any other variable.
:param name: display name
:param desc: verbose description
:param default: the default value
:param fire_event: Fire `addon:property:change` event, when modified
"""
# generated name for the attribute
h = "__Property" + str(hash(name) ^ hash(desc))
addonManager.addInfoProperty(h, name, desc)
def _get(self):
if not hasattr(self, h):
return default
return getattr(self, h)
def _set(self, value):
if fire_event:
self.manager.dispatchEvent("addon:property:change", value)
return setattr(self, h, value)
def _del(self):
return delattr(self, h)
return property(_get, _set, _del)
def threaded(f):
""" Decorator to run method in a thread. """
#@wraps(f)
def run(*args, **kwargs):
addonManager.startThread(f, *args, **kwargs)
return run
class Addon(Base):
"""
Base class for addon plugins. Use @threaded decorator for all longer running tasks.
Decorate methods with @Expose, @AddEventListener, @ConfigHandler
"""
#: periodic call interval in seconds
interval = 0
__type__ = "addon"
def __init__(self, core, manager, user=None):
Base.__init__(self, core, user)
#: Callback of periodical job task, used by addonManager
self.cb = None
#: `AddonManager`
self.manager = manager
self.init()
# start periodically if set
self.startPeriodical(self.interval, 0)
def startPeriodical(self, interval, wait):
""" Starts the periodical calls with given interval. Older entries will be canceled.
:param interval: interval in seconds
:param wait: time to wait in seconds before periodically starts
:return: True if s
"""
if interval < 1:
return False
# stop running callback
if self.cb:
self.stopPeriodical()
self.cb = self.core.scheduler.addJob(wait, self._periodical, threaded=False)
self.interval = interval
return True
def stopPeriodical(self):
""" Stops periodical call if existing
:return: True if the callback was stopped, false otherwise.
"""
if self.cb and self.core.scheduler.removeJob(self.cb):
self.cb = None
return True
else:
return False
def _periodical(self):
try:
if self.isActivated(): self.periodical()
except Exception, e:
self.core.log.error(_("Error executing addon: %s") % str(e))
self.core.print_exc()
if self.cb:
self.cb = self.core.scheduler.addJob(self.interval, self._periodical, threaded=False)
def __repr__(self):
return "<Addon %s>" % self.__name__
def isActivated(self):
""" checks if addon is activated"""
return True if self.__internal__ else self.getConfig("activated")
def getCategory(self):
return self.core.pluginManager.getCategory(self.__name__)
def init(self):
pass
def activate(self):
""" Used to activate the addon """
if has_method(self.__class__, "coreReady"):
self.logDebug("Deprecated method .coreReady() use activate() instead")
self.coreReady()
def deactivate(self):
""" Used to deactivate the addon. """
pass
def periodical(self):
pass
def newInteractionTask(self, task):
""" new interaction task for the plugin, it MUST set the handler and timeout or will be ignored """
pass
def taskCorrect(self, task):
pass
def taskInvalid(self, task):
pass
# public events starts from here
def downloadPreparing(self, pyfile):
pass
def downloadFinished(self, pyfile):
pass
def downloadFailed(self, pyfile):
pass
def packageFinished(self, pypack):
pass