├── .gitignore
├── README.md
├── gpl.txt
└── xbmc-vk.svoka.com
├── addon.xml
├── changelog.txt
├── default.py
├── icon.png
├── resources
├── language
│ ├── English
│ │ └── strings.xml
│ └── Russian
│ │ └── strings.xml
└── settings.xml
├── simplejson
├── __init__.py
├── decoder.py
├── encoder.py
├── scanner.py
└── tool.py
├── vk_auth.py
├── vkapicaller.py
├── vkapp.py
├── vkcookie.py
├── vkparsers.py
├── xbmcvkui.py
├── xvaudio.py
├── xvimage.py
└── xvvideo.py
/.gitignore:
--------------------------------------------------------------------------------
1 | \.pyo$
2 | \.pyc$
3 | \.bak$
4 | \.DS_Store
5 |
6 | xbmc-vk.svoka.com/gpl.txt
7 |
8 | .idea
9 |
10 | ^script
11 | ^packages
12 | ^plugin
13 | ^repository
14 | ^metadata
15 |
16 | test.py$
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Welcome / Привет
2 |
3 | You are reading vk-xbmc-plugin documentation.
4 | This add-on allows to browse media from VKontakte social network within XBMC media center.
5 |
6 |
7 | Вы читаете справку vk-xbmc-plugin.
8 | Это адд-он, расширение для медиацента XBMC, которое позволяет искать и просматривать самые разные медиа с ВКонтакта (сайтов vkontakte.ru и vk.com)
9 |
10 |
11 | ## Quick intro
12 | #### русский перевод ниже
13 |
14 | ### Info
15 | This is free software. Information about author and source code available at https://github.com/VkKodi/vkkodi
16 |
17 | ### Installation instruction
18 |
19 | * download latest zip release: https://github.com/VkKodi/repo/raw/master/addons/xbmc-vk.svoka.com.zip
20 | * in XBMC follow menu "SYSTEM -> Add-ons -> Install from zip file"
21 | * select downloaded file
22 | * return to main XBMC menu and select Video -> Video Addons -> VK-xmbc
23 | * wait for browser to appear and follow instructions to authorize application in VKontakte
24 | * you will be asked to enter your login email and password from VK social network (required to get videos)
25 | * Done!
26 |
27 | ### Usage
28 | If you did setup add-on properly, it is going to show you text input whenever you access it. Enter search string to look for video.
29 | After you'll get list of videos with preview pictures and length. After selectin name of video you should get list of available resolutions. Select one to begin playback.
30 |
31 | ### Notice
32 | This is free software in extremely early alpha. You can make it better by forking and contributing code, reporting issues or creating feature requests using [[https://github.com/VkKodi/vkkodi/issues|issue tracker]]
33 |
34 | **Cheers**
35 |
36 | ----
37 |
38 | ## Краткий курс об vk-xbmc-plugin
39 |
40 | ### Что? Где?
41 | Это свободное ПО. Информацию об авторе и всякое другое лежит по адресу https://github.com/VkKodi/vkkodi
42 |
43 | ### Установка
44 | * **XBMC версии 10 Dharma и выше: **:
45 | * скачайте последний zip файл: https://github.com/VkKodi/repo/raw/master/addons/xbmc-vk.svoka.com.zip
46 | * В XBMC меню откройте "SYSTEM -> Add-ons -> Install from zip file (Установка с zip архива)"
47 | * выберите скачанный только что файл
48 | * Вернитесь в главное меню XBMC, и выберите Video -> Video Addons -> VK-xmbc
49 | * При первом зпуске буте открыт браузер со страницей авторизации приложения во ВКонтакте. Нажмите ввод по окончанию авторизации
50 | * Если вы все правильно сделали и все работает, то приложение спросит у вас email и пароль от ВКонтакта. После этого покажет текстовое поле "search" для поиска
51 | * Все!
52 |
53 | ### Как использовать
54 | Если вы все правильно сделано и настроено, то при выборе VKontakte Search среди видео расширений XBMC у вас будет спрашиваться строка поиска. Напишите что-то там, нажмите ввод. После этого будет показан список найденных видео, с длинной и картинкой. Выберите наиболее подходящее видео и нажмите "Ввод/Enter". После этого можнете посмотреть доступность видео в разных разрешениях, выбрать подходящее и нажать, что бы проиграть.
55 | Приятного просмотра!
56 |
57 | ### Примечания
58 | Это свободное програмное обеспечение, на очень ранней стадии развития. Вы можете помочь дописывая код, или просто сообщая об ошибках.
59 |
60 | **Салют!**
61 |
--------------------------------------------------------------------------------
/gpl.txt:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/xbmc-vk.svoka.com/addon.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | image video audio
8 |
9 |
10 |
11 | https://raw.githubusercontent.com/VkKodi/repo/master/addons/addons.xml
12 | https://raw.githubusercontent.com/VkKodi/repo/master/addons/addons.xml.md5
13 | https://raw.githubusercontent.com/VkKodi/repo/master/addons
14 |
15 |
16 |
17 | Video, audio and photos from VKontakte social network http://vk.ru/
18 | Video from VKontakte social network http://vk.ru/
19 | homepage - http://github.com/VkKodi/vkkodi
20 | Author - Vlad Svoka aka Shchvova
21 | Видео с сайта http://vk.ru/
22 | Видео, аудио и фотографии с сайта http://vk.ru/
23 | Домашняя страница проекта - http://github.com/VkKodi/vkkodi
24 | Автор - Влад Свока aka Shchvova
25 | all
26 |
27 |
28 |
--------------------------------------------------------------------------------
/xbmc-vk.svoka.com/changelog.txt:
--------------------------------------------------------------------------------
1 | VK-xbmc
2 | Полноценный клиент ВКонтакта для медиацентра XBMC
3 |
4 | * Видео
5 | ** Поиск по видео
6 | ** В настройках дополнение есть возможность выбрать опцию "Только HD"
7 | ** Сохранение истории всех поисков поисков
8 | ** Каталоги
9 | *** Каталог самых популярных фильмов
10 | *** Каталог Сериалов с сезонами и названиями серий
11 | ** Возможность просматривать видео пользователя, Мои Видео
12 | * Аудио
13 | ** Возможность слушать свою аудиотеку во ВКонтакте
14 | ** Возможность поиска по аудиозаписям
15 | ** Сохранение истории поисков аудио
16 | ** Интересные артисты по версии Last FM
17 | * Фотографии
18 | ** Смотреть список альбомов пользователя
19 | ** Слайд-шоу по альбомам
20 |
21 |
22 |
--------------------------------------------------------------------------------
/xbmc-vk.svoka.com/default.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | # VK-XBMC add-on
4 | # Copyright (C) 2011 Volodymyr Shcherban
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | __author__ = 'Volodymyr Shcherban'
19 |
20 |
21 |
22 | import sys, os, xbmcaddon, xbmc, xbmcgui, xbmcplugin, urllib
23 |
24 | sys.path.append(xbmcaddon.Addon(id='xbmc-vk.svoka.com').getAddonInfo('path').decode('utf-8'))
25 |
26 | from vkapp import GetApi
27 |
28 | from xbmcvkui import HOME
29 | from xvaudio import XVKAudio
30 | from xvimage import XVKImage
31 | from xvvideo import XVKVideo
32 | import urlparse
33 |
34 | class XBMC_VK_UI_Factory:
35 | def GetUI(self, param, api, handle):
36 |
37 | content_type = param.get('content_type')
38 | if content_type == 'video':
39 | return XVKVideo(param, handle, api)
40 | elif content_type == 'audio':
41 | return XVKAudio(param, handle, api)
42 | elif content_type == 'image':
43 | return XVKImage(param, handle, api)
44 | #fallback if no content_type provided
45 | #bloody hacks http://wiki.xbmc.org/index.php?title=Window_IDs
46 | id = xbmcgui.getCurrentWindowId()
47 | if id in (10006, 10024, 10025, 10028):
48 | return XVKVideo(param, handle, api)
49 | elif id in (10005, 10500, 10501, 10502):
50 | return XVKAudio(param, handle, api)
51 | elif id in (10002,):
52 | return XVKImage(param, handle, api)
53 | else:
54 | print "Invalid context: " + str(id)
55 |
56 |
57 | def main():
58 | globHandle = int(sys.argv[1])
59 | globApi = GetApi()
60 | if globApi:
61 | params = {"mode": HOME}
62 | if sys.argv[2]:
63 | params.update(dict(urlparse.parse_qsl(sys.argv[2][1:])))
64 |
65 | XBMC_VK_UI_Factory().GetUI(params, globApi, globHandle)
66 |
67 | else:
68 | listItem = xbmcgui.ListItem("-- something wrong, try again --")
69 | xbmcplugin.addDirectoryItem(globHandle, sys.argv[0], listItem, True)
70 | xbmc.log("THIS IS THE END")
71 | raise Exception("Api is null")
72 |
73 |
74 | main()
75 |
--------------------------------------------------------------------------------
/xbmc-vk.svoka.com/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VkKodi/vkkodi/2ba5900f41972f6745054334850104cdeda3db57/xbmc-vk.svoka.com/icon.png
--------------------------------------------------------------------------------
/xbmc-vk.svoka.com/resources/language/English/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | VKontakte email
4 | Password
5 | Search video
6 | If browser didn't show up, open
7 | -- New VKontakte video search --
8 | Max history depth
9 | Search history
10 | -- New VKontakte audio search --
11 | My music
12 | Top grossing movies
13 | TV Shows
14 | My videos
15 | All Hail Shchvova
16 | Season %d, Episode %d
17 | Episode %s
18 | Hyped artists
19 | Only HD videos
20 | Sort videos by length
21 | Show only 'HD' results
22 | Log out from VK
23 | -- Home --
24 | 2FA Code
25 |
26 | Recomended music
27 | Popular music
28 |
29 | Downloads path
30 | Download/Open:
31 | Download:
32 | Select file name
33 | Incorrect setup!
34 | Setup "Download path" option to proceed
35 | Play:
36 | Download command
37 |
38 | Show download opiton
39 | Groups Video
40 | Friends
41 | -- Next Page (%d) --
42 |
43 | Auth token
44 | -- Previous Page (%d) --
45 | Safe search
46 | -- Albums --
47 |
48 |
49 |
--------------------------------------------------------------------------------
/xbmc-vk.svoka.com/resources/language/Russian/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | E-mail или Логин ВКонтакте
4 | Пароль
5 | Поиск видео
6 | Если браузер не запустился, откройте
7 | -- Новый поиск видео ВКонтакте --
8 | Максимум запросов в истории
9 | История поисков
10 | -- Новый поиск музыки ВКонтакте --
11 | Моя музыка
12 | Кассовые фильмы
13 | Сериалы
14 | Мои видео
15 | Слава Щвове! svoka.com
16 | Сезон %s, серия %s
17 | Серия %s
18 | Популярные исполнители
19 | Только HD видео
20 | Сортировка видео по длинне
21 | То же, только в HD
22 | Выйти из ВК
23 | -- Главное меню --
24 | Код авторизации
25 |
26 | Рекомендованная музыка
27 | Популярная музыка
28 |
29 | Сохранять файлы в...
30 | Скачать/Открыть:
31 | Скачать:
32 | Выберите имя файла
33 | Настройте путь для закачек!
34 | Выберите папку в настройке "Сохранять файлы в..."
35 | Смотреть:
36 | Команда скачивания
37 | Показывать вариант "скачать"
38 | Группы
39 | Друзья
40 | -- Следующая Страница (%d) --
41 | Ключ авторизации
42 | -- Предыдущая Страница (%d) --
43 | Безопасный поиск
44 | -- Альбомы --
45 |
46 |
--------------------------------------------------------------------------------
/xbmc-vk.svoka.com/resources/settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/xbmc-vk.svoka.com/simplejson/__init__.py:
--------------------------------------------------------------------------------
1 | r"""JSON (JavaScript Object Notation) is a subset of
2 | JavaScript syntax (ECMA-262 3rd edition) used as a lightweight data
3 | interchange format.
4 |
5 | :mod:`simplejson` exposes an API familiar to users of the standard library
6 | :mod:`marshal` and :mod:`pickle` modules. It is the externally maintained
7 | version of the :mod:`json` library contained in Python 2.6, but maintains
8 | compatibility with Python 2.4 and Python 2.5 and (currently) has
9 | significant performance advantages, even without using the optional C
10 | extension for speedups.
11 |
12 | Encoding basic Python object hierarchies::
13 |
14 | >>> import simplejson as json
15 | >>> json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}])
16 | '["foo", {"bar": ["baz", null, 1.0, 2]}]'
17 | >>> print json.dumps("\"foo\bar")
18 | "\"foo\bar"
19 | >>> print json.dumps(u'\u1234')
20 | "\u1234"
21 | >>> print json.dumps('\\')
22 | "\\"
23 | >>> print json.dumps({"c": 0, "b": 0, "a": 0}, sort_keys=True)
24 | {"a": 0, "b": 0, "c": 0}
25 | >>> from StringIO import StringIO
26 | >>> io = StringIO()
27 | >>> json.dump(['streaming API'], io)
28 | >>> io.getvalue()
29 | '["streaming API"]'
30 |
31 | Compact encoding::
32 |
33 | >>> import simplejson as json
34 | >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':'))
35 | '[1,2,3,{"4":5,"6":7}]'
36 |
37 | Pretty printing::
38 |
39 | >>> import simplejson as json
40 | >>> s = json.dumps({'4': 5, '6': 7}, sort_keys=True, indent=4)
41 | >>> print '\n'.join([l.rstrip() for l in s.splitlines()])
42 | {
43 | "4": 5,
44 | "6": 7
45 | }
46 |
47 | Decoding JSON::
48 |
49 | >>> import simplejson as json
50 | >>> obj = [u'foo', {u'bar': [u'baz', None, 1.0, 2]}]
51 | >>> json.loads('["foo", {"bar":["baz", null, 1.0, 2]}]') == obj
52 | True
53 | >>> json.loads('"\\"foo\\bar"') == u'"foo\x08ar'
54 | True
55 | >>> from StringIO import StringIO
56 | >>> io = StringIO('["streaming API"]')
57 | >>> json.load(io)[0] == 'streaming API'
58 | True
59 |
60 | Specializing JSON object decoding::
61 |
62 | >>> import simplejson as json
63 | >>> def as_complex(dct):
64 | ... if '__complex__' in dct:
65 | ... return complex(dct['real'], dct['imag'])
66 | ... return dct
67 | ...
68 | >>> json.loads('{"__complex__": true, "real": 1, "imag": 2}',
69 | ... object_hook=as_complex)
70 | (1+2j)
71 | >>> import decimal
72 | >>> json.loads('1.1', parse_float=decimal.Decimal) == decimal.Decimal('1.1')
73 | True
74 |
75 | Specializing JSON object encoding::
76 |
77 | >>> import simplejson as json
78 | >>> def encode_complex(obj):
79 | ... if isinstance(obj, complex):
80 | ... return [obj.real, obj.imag]
81 | ... raise TypeError("%r is not JSON serializable" % (o,))
82 | ...
83 | >>> json.dumps(2 + 1j, default=encode_complex)
84 | '[2.0, 1.0]'
85 | >>> json.JSONEncoder(default=encode_complex).encode(2 + 1j)
86 | '[2.0, 1.0]'
87 | >>> ''.join(json.JSONEncoder(default=encode_complex).iterencode(2 + 1j))
88 | '[2.0, 1.0]'
89 |
90 |
91 | Using simplejson.tool from the shell to validate and pretty-print::
92 |
93 | $ echo '{"json":"obj"}' | python -msimplejson.tool
94 | {
95 | "json": "obj"
96 | }
97 | $ echo '{ 1.2:3.4}' | python -msimplejson.tool
98 | Expecting property name: line 1 column 2 (char 2)
99 | """
100 | __version__ = '2.0.7'
101 | __all__ = [
102 | 'dump', 'dumps', 'load', 'loads',
103 | 'JSONDecoder', 'JSONEncoder',
104 | ]
105 |
106 | from decoder import JSONDecoder
107 | from encoder import JSONEncoder
108 |
109 | _default_encoder = JSONEncoder(
110 | skipkeys=False,
111 | ensure_ascii=True,
112 | check_circular=True,
113 | allow_nan=True,
114 | indent=None,
115 | separators=None,
116 | encoding='utf-8',
117 | default=None,
118 | )
119 |
120 | def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True,
121 | allow_nan=True, cls=None, indent=None, separators=None,
122 | encoding='utf-8', default=None, **kw):
123 | """Serialize ``obj`` as a JSON formatted stream to ``fp`` (a
124 | ``.write()``-supporting file-like object).
125 |
126 | If ``skipkeys`` is ``True`` then ``dict`` keys that are not basic types
127 | (``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``)
128 | will be skipped instead of raising a ``TypeError``.
129 |
130 | If ``ensure_ascii`` is ``False``, then the some chunks written to ``fp``
131 | may be ``unicode`` instances, subject to normal Python ``str`` to
132 | ``unicode`` coercion rules. Unless ``fp.write()`` explicitly
133 | understands ``unicode`` (as in ``codecs.getwriter()``) this is likely
134 | to cause an error.
135 |
136 | If ``check_circular`` is ``False``, then the circular reference check
137 | for container types will be skipped and a circular reference will
138 | result in an ``OverflowError`` (or worse).
139 |
140 | If ``allow_nan`` is ``False``, then it will be a ``ValueError`` to
141 | serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``)
142 | in strict compliance of the JSON specification, instead of using the
143 | JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``).
144 |
145 | If ``indent`` is a non-negative integer, then JSON array elements and object
146 | members will be pretty-printed with that indent level. An indent level
147 | of 0 will only insert newlines. ``None`` is the most compact representation.
148 |
149 | If ``separators`` is an ``(item_separator, dict_separator)`` tuple
150 | then it will be used instead of the default ``(', ', ': ')`` separators.
151 | ``(',', ':')`` is the most compact JSON representation.
152 |
153 | ``encoding`` is the character encoding for str instances, default is UTF-8.
154 |
155 | ``default(obj)`` is a function that should return a serializable version
156 | of obj or raise TypeError. The default simply raises TypeError.
157 |
158 | To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the
159 | ``.default()`` method to serialize additional types), specify it with
160 | the ``cls`` kwarg.
161 |
162 | """
163 | # cached encoder
164 | if (skipkeys is False and ensure_ascii is True and
165 | check_circular is True and allow_nan is True and
166 | cls is None and indent is None and separators is None and
167 | encoding == 'utf-8' and default is None and not kw):
168 | iterable = _default_encoder.iterencode(obj)
169 | else:
170 | if cls is None:
171 | cls = JSONEncoder
172 | iterable = cls(skipkeys=skipkeys, ensure_ascii=ensure_ascii,
173 | check_circular=check_circular, allow_nan=allow_nan, indent=indent,
174 | separators=separators, encoding=encoding,
175 | default=default, **kw).iterencode(obj)
176 | # could accelerate with writelines in some versions of Python, at
177 | # a debuggability cost
178 | for chunk in iterable:
179 | fp.write(chunk)
180 |
181 |
182 | def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True,
183 | allow_nan=True, cls=None, indent=None, separators=None,
184 | encoding='utf-8', default=None, **kw):
185 | """Serialize ``obj`` to a JSON formatted ``str``.
186 |
187 | If ``skipkeys`` is ``True`` then ``dict`` keys that are not basic types
188 | (``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``)
189 | will be skipped instead of raising a ``TypeError``.
190 |
191 | If ``ensure_ascii`` is ``False``, then the return value will be a
192 | ``unicode`` instance subject to normal Python ``str`` to ``unicode``
193 | coercion rules instead of being escaped to an ASCII ``str``.
194 |
195 | If ``check_circular`` is ``False``, then the circular reference check
196 | for container types will be skipped and a circular reference will
197 | result in an ``OverflowError`` (or worse).
198 |
199 | If ``allow_nan`` is ``False``, then it will be a ``ValueError`` to
200 | serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``) in
201 | strict compliance of the JSON specification, instead of using the
202 | JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``).
203 |
204 | If ``indent`` is a non-negative integer, then JSON array elements and
205 | object members will be pretty-printed with that indent level. An indent
206 | level of 0 will only insert newlines. ``None`` is the most compact
207 | representation.
208 |
209 | If ``separators`` is an ``(item_separator, dict_separator)`` tuple
210 | then it will be used instead of the default ``(', ', ': ')`` separators.
211 | ``(',', ':')`` is the most compact JSON representation.
212 |
213 | ``encoding`` is the character encoding for str instances, default is UTF-8.
214 |
215 | ``default(obj)`` is a function that should return a serializable version
216 | of obj or raise TypeError. The default simply raises TypeError.
217 |
218 | To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the
219 | ``.default()`` method to serialize additional types), specify it with
220 | the ``cls`` kwarg.
221 |
222 | """
223 | # cached encoder
224 | if (skipkeys is False and ensure_ascii is True and
225 | check_circular is True and allow_nan is True and
226 | cls is None and indent is None and separators is None and
227 | encoding == 'utf-8' and default is None and not kw):
228 | return _default_encoder.encode(obj)
229 | if cls is None:
230 | cls = JSONEncoder
231 | return cls(
232 | skipkeys=skipkeys, ensure_ascii=ensure_ascii,
233 | check_circular=check_circular, allow_nan=allow_nan, indent=indent,
234 | separators=separators, encoding=encoding, default=default,
235 | **kw).encode(obj)
236 |
237 |
238 | _default_decoder = JSONDecoder(encoding=None, object_hook=None)
239 |
240 |
241 | def load(fp, encoding=None, cls=None, object_hook=None, parse_float=None,
242 | parse_int=None, parse_constant=None, **kw):
243 | """Deserialize ``fp`` (a ``.read()``-supporting file-like object containing
244 | a JSON document) to a Python object.
245 |
246 | If the contents of ``fp`` is encoded with an ASCII based encoding other
247 | than utf-8 (e.g. latin-1), then an appropriate ``encoding`` name must
248 | be specified. Encodings that are not ASCII based (such as UCS-2) are
249 | not allowed, and should be wrapped with
250 | ``codecs.getreader(fp)(encoding)``, or simply decoded to a ``unicode``
251 | object and passed to ``loads()``
252 |
253 | ``object_hook`` is an optional function that will be called with the
254 | result of any object literal decode (a ``dict``). The return value of
255 | ``object_hook`` will be used instead of the ``dict``. This feature
256 | can be used to implement custom decoders (e.g. JSON-RPC class hinting).
257 |
258 | To use a custom ``JSONDecoder`` subclass, specify it with the ``cls``
259 | kwarg.
260 |
261 | """
262 | return loads(fp.read(),
263 | encoding=encoding, cls=cls, object_hook=object_hook,
264 | parse_float=parse_float, parse_int=parse_int,
265 | parse_constant=parse_constant, **kw)
266 |
267 |
268 | def loads(s, encoding=None, cls=None, object_hook=None, parse_float=None,
269 | parse_int=None, parse_constant=None, **kw):
270 | """Deserialize ``s`` (a ``str`` or ``unicode`` instance containing a JSON
271 | document) to a Python object.
272 |
273 | If ``s`` is a ``str`` instance and is encoded with an ASCII based encoding
274 | other than utf-8 (e.g. latin-1) then an appropriate ``encoding`` name
275 | must be specified. Encodings that are not ASCII based (such as UCS-2)
276 | are not allowed and should be decoded to ``unicode`` first.
277 |
278 | ``object_hook`` is an optional function that will be called with the
279 | result of any object literal decode (a ``dict``). The return value of
280 | ``object_hook`` will be used instead of the ``dict``. This feature
281 | can be used to implement custom decoders (e.g. JSON-RPC class hinting).
282 |
283 | ``parse_float``, if specified, will be called with the string
284 | of every JSON float to be decoded. By default this is equivalent to
285 | float(num_str). This can be used to use another datatype or parser
286 | for JSON floats (e.g. decimal.Decimal).
287 |
288 | ``parse_int``, if specified, will be called with the string
289 | of every JSON int to be decoded. By default this is equivalent to
290 | int(num_str). This can be used to use another datatype or parser
291 | for JSON integers (e.g. float).
292 |
293 | ``parse_constant``, if specified, will be called with one of the
294 | following strings: -Infinity, Infinity, NaN, null, true, false.
295 | This can be used to raise an exception if invalid JSON numbers
296 | are encountered.
297 |
298 | To use a custom ``JSONDecoder`` subclass, specify it with the ``cls``
299 | kwarg.
300 |
301 | """
302 | if (cls is None and encoding is None and object_hook is None and
303 | parse_int is None and parse_float is None and
304 | parse_constant is None and not kw):
305 | return _default_decoder.decode(s)
306 | if cls is None:
307 | cls = JSONDecoder
308 | if object_hook is not None:
309 | kw['object_hook'] = object_hook
310 | if parse_float is not None:
311 | kw['parse_float'] = parse_float
312 | if parse_int is not None:
313 | kw['parse_int'] = parse_int
314 | if parse_constant is not None:
315 | kw['parse_constant'] = parse_constant
316 | return cls(encoding=encoding, **kw).decode(s)
317 |
--------------------------------------------------------------------------------
/xbmc-vk.svoka.com/simplejson/decoder.py:
--------------------------------------------------------------------------------
1 | """Implementation of JSONDecoder
2 | """
3 | import re
4 | import sys
5 | import struct
6 |
7 | from simplejson.scanner import make_scanner
8 | try:
9 | from simplejson._speedups import scanstring as c_scanstring
10 | except ImportError:
11 | c_scanstring = None
12 |
13 | __all__ = ['JSONDecoder']
14 |
15 | FLAGS = re.VERBOSE | re.MULTILINE | re.DOTALL
16 |
17 | def _floatconstants():
18 | _BYTES = '7FF80000000000007FF0000000000000'.decode('hex')
19 | if sys.byteorder != 'big':
20 | _BYTES = _BYTES[:8][::-1] + _BYTES[8:][::-1]
21 | nan, inf = struct.unpack('dd', _BYTES)
22 | return nan, inf, -inf
23 |
24 | NaN, PosInf, NegInf = _floatconstants()
25 |
26 |
27 | def linecol(doc, pos):
28 | lineno = doc.count('\n', 0, pos) + 1
29 | if lineno == 1:
30 | colno = pos
31 | else:
32 | colno = pos - doc.rindex('\n', 0, pos)
33 | return lineno, colno
34 |
35 |
36 | def errmsg(msg, doc, pos, end=None):
37 | # Note that this function is called from _speedups
38 | lineno, colno = linecol(doc, pos)
39 | if end is None:
40 | return '%s: line %d column %d (char %d)' % (msg, lineno, colno, pos)
41 | endlineno, endcolno = linecol(doc, end)
42 | return '%s: line %d column %d - line %d column %d (char %d - %d)' % (
43 | msg, lineno, colno, endlineno, endcolno, pos, end)
44 |
45 |
46 | _CONSTANTS = {
47 | '-Infinity': NegInf,
48 | 'Infinity': PosInf,
49 | 'NaN': NaN,
50 | }
51 |
52 | STRINGCHUNK = re.compile(r'(.*?)(["\\\x00-\x1f])', FLAGS)
53 | BACKSLASH = {
54 | '"': u'"', '\\': u'\\', '/': u'/',
55 | 'b': u'\b', 'f': u'\f', 'n': u'\n', 'r': u'\r', 't': u'\t',
56 | }
57 |
58 | DEFAULT_ENCODING = "utf-8"
59 |
60 | def py_scanstring(s, end, encoding=None, strict=True, _b=BACKSLASH, _m=STRINGCHUNK.match):
61 | """Scan the string s for a JSON string. End is the index of the
62 | character in s after the quote that started the JSON string.
63 | Unescapes all valid JSON string escape sequences and raises ValueError
64 | on attempt to decode an invalid string. If strict is False then literal
65 | control characters are allowed in the string.
66 |
67 | Returns a tuple of the decoded string and the index of the character in s
68 | after the end quote."""
69 | if encoding is None:
70 | encoding = DEFAULT_ENCODING
71 | chunks = []
72 | _append = chunks.append
73 | begin = end - 1
74 | while 1:
75 | chunk = _m(s, end)
76 | if chunk is None:
77 | raise ValueError(
78 | errmsg("Unterminated string starting at", s, begin))
79 | end = chunk.end()
80 | content, terminator = chunk.groups()
81 | # Content is contains zero or more unescaped string characters
82 | if content:
83 | if not isinstance(content, unicode):
84 | content = unicode(content, encoding)
85 | _append(content)
86 | # Terminator is the end of string, a literal control character,
87 | # or a backslash denoting that an escape sequence follows
88 | if terminator == '"':
89 | break
90 | elif terminator != '\\':
91 | if strict:
92 | msg = "Invalid control character %r at" % (terminator,)
93 | raise ValueError(msg, s, end)
94 | else:
95 | _append(terminator)
96 | continue
97 | try:
98 | esc = s[end]
99 | except IndexError:
100 | raise ValueError(
101 | errmsg("Unterminated string starting at", s, begin))
102 | # If not a unicode escape sequence, must be in the lookup table
103 | if esc != 'u':
104 | try:
105 | char = _b[esc]
106 | except KeyError:
107 | raise ValueError(
108 | errmsg("Invalid \\escape: %r" % (esc,), s, end))
109 | end += 1
110 | else:
111 | # Unicode escape sequence
112 | esc = s[end + 1:end + 5]
113 | next_end = end + 5
114 | if len(esc) != 4:
115 | msg = "Invalid \\uXXXX escape"
116 | raise ValueError(errmsg(msg, s, end))
117 | uni = int(esc, 16)
118 | # Check for surrogate pair on UCS-4 systems
119 | if 0xd800 <= uni <= 0xdbff and sys.maxunicode > 65535:
120 | msg = "Invalid \\uXXXX\\uXXXX surrogate pair"
121 | if not s[end + 5:end + 7] == '\\u':
122 | raise ValueError(errmsg(msg, s, end))
123 | esc2 = s[end + 7:end + 11]
124 | if len(esc2) != 4:
125 | raise ValueError(errmsg(msg, s, end))
126 | uni2 = int(esc2, 16)
127 | uni = 0x10000 + (((uni - 0xd800) << 10) | (uni2 - 0xdc00))
128 | next_end += 6
129 | char = unichr(uni)
130 | end = next_end
131 | # Append the unescaped character
132 | _append(char)
133 | return u''.join(chunks), end
134 |
135 |
136 | # Use speedup if available
137 | scanstring = c_scanstring or py_scanstring
138 |
139 | WHITESPACE = re.compile(r'[ \t\n\r]*', FLAGS)
140 | WHITESPACE_STR = ' \t\n\r'
141 |
142 | def JSONObject((s, end), encoding, strict, scan_once, object_hook, _w=WHITESPACE.match, _ws=WHITESPACE_STR):
143 | pairs = {}
144 | # Use a slice to prevent IndexError from being raised, the following
145 | # check will raise a more specific ValueError if the string is empty
146 | nextchar = s[end:end + 1]
147 | # Normally we expect nextchar == '"'
148 | if nextchar != '"':
149 | if nextchar in _ws:
150 | end = _w(s, end).end()
151 | nextchar = s[end:end + 1]
152 | # Trivial empty object
153 | if nextchar == '}':
154 | return pairs, end + 1
155 | elif nextchar != '"':
156 | raise ValueError(errmsg("Expecting property name", s, end))
157 | end += 1
158 | while True:
159 | key, end = scanstring(s, end, encoding, strict)
160 |
161 | # To skip some function call overhead we optimize the fast paths where
162 | # the JSON key separator is ": " or just ":".
163 | if s[end:end + 1] != ':':
164 | end = _w(s, end).end()
165 | if s[end:end + 1] != ':':
166 | raise ValueError(errmsg("Expecting : delimiter", s, end))
167 |
168 | end += 1
169 |
170 | try:
171 | if s[end] in _ws:
172 | end += 1
173 | if s[end] in _ws:
174 | end = _w(s, end + 1).end()
175 | except IndexError:
176 | pass
177 |
178 | try:
179 | value, end = scan_once(s, end)
180 | except StopIteration:
181 | raise ValueError(errmsg("Expecting object", s, end))
182 | pairs[key] = value
183 |
184 | try:
185 | nextchar = s[end]
186 | if nextchar in _ws:
187 | end = _w(s, end + 1).end()
188 | nextchar = s[end]
189 | except IndexError:
190 | nextchar = ''
191 | end += 1
192 |
193 | if nextchar == '}':
194 | break
195 | elif nextchar != ',':
196 | raise ValueError(errmsg("Expecting , delimiter", s, end - 1))
197 |
198 | try:
199 | nextchar = s[end]
200 | if nextchar in _ws:
201 | end += 1
202 | nextchar = s[end]
203 | if nextchar in _ws:
204 | end = _w(s, end + 1).end()
205 | nextchar = s[end]
206 | except IndexError:
207 | nextchar = ''
208 |
209 | end += 1
210 | if nextchar != '"':
211 | raise ValueError(errmsg("Expecting property name", s, end - 1))
212 |
213 | if object_hook is not None:
214 | pairs = object_hook(pairs)
215 | return pairs, end
216 |
217 | def JSONArray((s, end), scan_once, _w=WHITESPACE.match, _ws=WHITESPACE_STR):
218 | values = []
219 | nextchar = s[end:end + 1]
220 | if nextchar in _ws:
221 | end = _w(s, end + 1).end()
222 | nextchar = s[end:end + 1]
223 | # Look-ahead for trivial empty array
224 | if nextchar == ']':
225 | return values, end + 1
226 | _append = values.append
227 | while True:
228 | try:
229 | value, end = scan_once(s, end)
230 | except StopIteration:
231 | raise ValueError(errmsg("Expecting object", s, end))
232 | _append(value)
233 | nextchar = s[end:end + 1]
234 | if nextchar in _ws:
235 | end = _w(s, end + 1).end()
236 | nextchar = s[end:end + 1]
237 | end += 1
238 | if nextchar == ']':
239 | break
240 | elif nextchar != ',':
241 | raise ValueError(errmsg("Expecting , delimiter", s, end))
242 |
243 | try:
244 | if s[end] in _ws:
245 | end += 1
246 | if s[end] in _ws:
247 | end = _w(s, end + 1).end()
248 | except IndexError:
249 | pass
250 |
251 | return values, end
252 |
253 | class JSONDecoder(object):
254 | """Simple JSON decoder
255 |
256 | Performs the following translations in decoding by default:
257 |
258 | +---------------+-------------------+
259 | | JSON | Python |
260 | +===============+===================+
261 | | object | dict |
262 | +---------------+-------------------+
263 | | array | list |
264 | +---------------+-------------------+
265 | | string | unicode |
266 | +---------------+-------------------+
267 | | number (int) | int, long |
268 | +---------------+-------------------+
269 | | number (real) | float |
270 | +---------------+-------------------+
271 | | true | True |
272 | +---------------+-------------------+
273 | | false | False |
274 | +---------------+-------------------+
275 | | null | None |
276 | +---------------+-------------------+
277 |
278 | It also understands ``NaN``, ``Infinity``, and ``-Infinity`` as
279 | their corresponding ``float`` values, which is outside the JSON spec.
280 |
281 | """
282 |
283 | def __init__(self, encoding=None, object_hook=None, parse_float=None,
284 | parse_int=None, parse_constant=None, strict=True):
285 | """``encoding`` determines the encoding used to interpret any ``str``
286 | objects decoded by this instance (utf-8 by default). It has no
287 | effect when decoding ``unicode`` objects.
288 |
289 | Note that currently only encodings that are a superset of ASCII work,
290 | strings of other encodings should be passed in as ``unicode``.
291 |
292 | ``object_hook``, if specified, will be called with the result
293 | of every JSON object decoded and its return value will be used in
294 | place of the given ``dict``. This can be used to provide custom
295 | deserializations (e.g. to support JSON-RPC class hinting).
296 |
297 | ``parse_float``, if specified, will be called with the string
298 | of every JSON float to be decoded. By default this is equivalent to
299 | float(num_str). This can be used to use another datatype or parser
300 | for JSON floats (e.g. decimal.Decimal).
301 |
302 | ``parse_int``, if specified, will be called with the string
303 | of every JSON int to be decoded. By default this is equivalent to
304 | int(num_str). This can be used to use another datatype or parser
305 | for JSON integers (e.g. float).
306 |
307 | ``parse_constant``, if specified, will be called with one of the
308 | following strings: -Infinity, Infinity, NaN.
309 | This can be used to raise an exception if invalid JSON numbers
310 | are encountered.
311 |
312 | """
313 | self.encoding = encoding
314 | self.object_hook = object_hook
315 | self.parse_float = parse_float or float
316 | self.parse_int = parse_int or int
317 | self.parse_constant = parse_constant or _CONSTANTS.__getitem__
318 | self.strict = strict
319 | self.parse_object = JSONObject
320 | self.parse_array = JSONArray
321 | self.parse_string = scanstring
322 | self.scan_once = make_scanner(self)
323 |
324 | def decode(self, s, _w=WHITESPACE.match):
325 | """Return the Python representation of ``s`` (a ``str`` or ``unicode``
326 | instance containing a JSON document)
327 |
328 | """
329 | obj, end = self.raw_decode(s, idx=_w(s, 0).end())
330 | end = _w(s, end).end()
331 | if end != len(s):
332 | raise ValueError(errmsg("Extra data", s, end, len(s)))
333 | return obj
334 |
335 | def raw_decode(self, s, idx=0):
336 | """Decode a JSON document from ``s`` (a ``str`` or ``unicode`` beginning
337 | with a JSON document) and return a 2-tuple of the Python
338 | representation and the index in ``s`` where the document ended.
339 |
340 | This can be used to decode a JSON document from a string that may
341 | have extraneous data at the end.
342 |
343 | """
344 | try:
345 | obj, end = self.scan_once(s, idx)
346 | except StopIteration:
347 | raise ValueError("No JSON object could be decoded")
348 | return obj, end
349 |
--------------------------------------------------------------------------------
/xbmc-vk.svoka.com/simplejson/encoder.py:
--------------------------------------------------------------------------------
1 | """Implementation of JSONEncoder
2 | """
3 | import re
4 |
5 | try:
6 | from simplejson._speedups import encode_basestring_ascii as c_encode_basestring_ascii
7 | except ImportError:
8 | c_encode_basestring_ascii = None
9 | try:
10 | from simplejson._speedups import make_encoder as c_make_encoder
11 | except ImportError:
12 | c_make_encoder = None
13 |
14 | ESCAPE = re.compile(r'[\x00-\x1f\\"\b\f\n\r\t]')
15 | ESCAPE_ASCII = re.compile(r'([\\"]|[^\ -~])')
16 | HAS_UTF8 = re.compile(r'[\x80-\xff]')
17 | ESCAPE_DCT = {
18 | '\\': '\\\\',
19 | '"': '\\"',
20 | '\b': '\\b',
21 | '\f': '\\f',
22 | '\n': '\\n',
23 | '\r': '\\r',
24 | '\t': '\\t',
25 | }
26 | for i in range(0x20):
27 | ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,))
28 |
29 | # Assume this produces an infinity on all machines (probably not guaranteed)
30 | INFINITY = float('1e66666')
31 | FLOAT_REPR = repr
32 |
33 | def encode_basestring(s):
34 | """Return a JSON representation of a Python string
35 |
36 | """
37 | def replace(match):
38 | return ESCAPE_DCT[match.group(0)]
39 | return '"' + ESCAPE.sub(replace, s) + '"'
40 |
41 |
42 | def py_encode_basestring_ascii(s):
43 | """Return an ASCII-only JSON representation of a Python string
44 |
45 | """
46 | if isinstance(s, str) and HAS_UTF8.search(s) is not None:
47 | s = s.decode('utf-8')
48 | def replace(match):
49 | s = match.group(0)
50 | try:
51 | return ESCAPE_DCT[s]
52 | except KeyError:
53 | n = ord(s)
54 | if n < 0x10000:
55 | return '\\u%04x' % (n,)
56 | else:
57 | # surrogate pair
58 | n -= 0x10000
59 | s1 = 0xd800 | ((n >> 10) & 0x3ff)
60 | s2 = 0xdc00 | (n & 0x3ff)
61 | return '\\u%04x\\u%04x' % (s1, s2)
62 | return '"' + str(ESCAPE_ASCII.sub(replace, s)) + '"'
63 |
64 |
65 | encode_basestring_ascii = c_encode_basestring_ascii or py_encode_basestring_ascii
66 |
67 | class JSONEncoder(object):
68 | """Extensible JSON encoder for Python data structures.
69 |
70 | Supports the following objects and types by default:
71 |
72 | +-------------------+---------------+
73 | | Python | JSON |
74 | +===================+===============+
75 | | dict | object |
76 | +-------------------+---------------+
77 | | list, tuple | array |
78 | +-------------------+---------------+
79 | | str, unicode | string |
80 | +-------------------+---------------+
81 | | int, long, float | number |
82 | +-------------------+---------------+
83 | | True | true |
84 | +-------------------+---------------+
85 | | False | false |
86 | +-------------------+---------------+
87 | | None | null |
88 | +-------------------+---------------+
89 |
90 | To extend this to recognize other objects, subclass and implement a
91 | ``.default()`` method with another method that returns a serializable
92 | object for ``o`` if possible, otherwise it should call the superclass
93 | implementation (to raise ``TypeError``).
94 |
95 | """
96 | item_separator = ', '
97 | key_separator = ': '
98 | def __init__(self, skipkeys=False, ensure_ascii=True,
99 | check_circular=True, allow_nan=True, sort_keys=False,
100 | indent=None, separators=None, encoding='utf-8', default=None):
101 | """Constructor for JSONEncoder, with sensible defaults.
102 |
103 | If skipkeys is False, then it is a TypeError to attempt
104 | encoding of keys that are not str, int, long, float or None. If
105 | skipkeys is True, such items are simply skipped.
106 |
107 | If ensure_ascii is True, the output is guaranteed to be str
108 | objects with all incoming unicode characters escaped. If
109 | ensure_ascii is false, the output will be unicode object.
110 |
111 | If check_circular is True, then lists, dicts, and custom encoded
112 | objects will be checked for circular references during encoding to
113 | prevent an infinite recursion (which would cause an OverflowError).
114 | Otherwise, no such check takes place.
115 |
116 | If allow_nan is True, then NaN, Infinity, and -Infinity will be
117 | encoded as such. This behavior is not JSON specification compliant,
118 | but is consistent with most JavaScript based encoders and decoders.
119 | Otherwise, it will be a ValueError to encode such floats.
120 |
121 | If sort_keys is True, then the output of dictionaries will be
122 | sorted by key; this is useful for regression tests to ensure
123 | that JSON serializations can be compared on a day-to-day basis.
124 |
125 | If indent is a non-negative integer, then JSON array
126 | elements and object members will be pretty-printed with that
127 | indent level. An indent level of 0 will only insert newlines.
128 | None is the most compact representation.
129 |
130 | If specified, separators should be a (item_separator, key_separator)
131 | tuple. The default is (', ', ': '). To get the most compact JSON
132 | representation you should specify (',', ':') to eliminate whitespace.
133 |
134 | If specified, default is a function that gets called for objects
135 | that can't otherwise be serialized. It should return a JSON encodable
136 | version of the object or raise a ``TypeError``.
137 |
138 | If encoding is not None, then all input strings will be
139 | transformed into unicode using that encoding prior to JSON-encoding.
140 | The default is UTF-8.
141 |
142 | """
143 |
144 | self.skipkeys = skipkeys
145 | self.ensure_ascii = ensure_ascii
146 | self.check_circular = check_circular
147 | self.allow_nan = allow_nan
148 | self.sort_keys = sort_keys
149 | self.indent = indent
150 | if separators is not None:
151 | self.item_separator, self.key_separator = separators
152 | if default is not None:
153 | self.default = default
154 | self.encoding = encoding
155 |
156 | def default(self, o):
157 | """Implement this method in a subclass such that it returns
158 | a serializable object for ``o``, or calls the base implementation
159 | (to raise a ``TypeError``).
160 |
161 | For example, to support arbitrary iterators, you could
162 | implement default like this::
163 |
164 | def default(self, o):
165 | try:
166 | iterable = iter(o)
167 | except TypeError:
168 | pass
169 | else:
170 | return list(iterable)
171 | return JSONEncoder.default(self, o)
172 |
173 | """
174 | raise TypeError("%r is not JSON serializable" % (o,))
175 |
176 | def encode(self, o):
177 | """Return a JSON string representation of a Python data structure.
178 |
179 | >>> JSONEncoder().encode({"foo": ["bar", "baz"]})
180 | '{"foo": ["bar", "baz"]}'
181 |
182 | """
183 | # This is for extremely simple cases and benchmarks.
184 | if isinstance(o, basestring):
185 | if isinstance(o, str):
186 | _encoding = self.encoding
187 | if (_encoding is not None
188 | and not (_encoding == 'utf-8')):
189 | o = o.decode(_encoding)
190 | if self.ensure_ascii:
191 | return encode_basestring_ascii(o)
192 | else:
193 | return encode_basestring(o)
194 | # This doesn't pass the iterator directly to ''.join() because the
195 | # exceptions aren't as detailed. The list call should be roughly
196 | # equivalent to the PySequence_Fast that ''.join() would do.
197 | chunks = self.iterencode(o, _one_shot=True)
198 | if not isinstance(chunks, (list, tuple)):
199 | chunks = list(chunks)
200 | return ''.join(chunks)
201 |
202 | def iterencode(self, o, _one_shot=False):
203 | """Encode the given object and yield each string
204 | representation as available.
205 |
206 | For example::
207 |
208 | for chunk in JSONEncoder().iterencode(bigobject):
209 | mysocket.write(chunk)
210 |
211 | """
212 | if self.check_circular:
213 | markers = {}
214 | else:
215 | markers = None
216 | if self.ensure_ascii:
217 | _encoder = encode_basestring_ascii
218 | else:
219 | _encoder = encode_basestring
220 | if self.encoding != 'utf-8':
221 | def _encoder(o, _orig_encoder=_encoder, _encoding=self.encoding):
222 | if isinstance(o, str):
223 | o = o.decode(_encoding)
224 | return _orig_encoder(o)
225 |
226 | def floatstr(o, allow_nan=self.allow_nan, _repr=FLOAT_REPR, _inf=INFINITY, _neginf=-INFINITY):
227 | # Check for specials. Note that this type of test is processor- and/or
228 | # platform-specific, so do tests which don't depend on the internals.
229 |
230 | if o != o:
231 | text = 'NaN'
232 | elif o == _inf:
233 | text = 'Infinity'
234 | elif o == _neginf:
235 | text = '-Infinity'
236 | else:
237 | return _repr(o)
238 |
239 | if not allow_nan:
240 | raise ValueError("Out of range float values are not JSON compliant: %r"
241 | % (o,))
242 |
243 | return text
244 |
245 |
246 | if _one_shot and c_make_encoder is not None and not self.indent and not self.sort_keys:
247 | _iterencode = c_make_encoder(
248 | markers, self.default, _encoder, self.indent,
249 | self.key_separator, self.item_separator, self.sort_keys,
250 | self.skipkeys, self.allow_nan)
251 | else:
252 | _iterencode = _make_iterencode(
253 | markers, self.default, _encoder, self.indent, floatstr,
254 | self.key_separator, self.item_separator, self.sort_keys,
255 | self.skipkeys, _one_shot)
256 | return _iterencode(o, 0)
257 |
258 | def _make_iterencode(markers, _default, _encoder, _indent, _floatstr, _key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot,
259 | ## HACK: hand-optimized bytecode; turn globals into locals
260 | False=False,
261 | True=True,
262 | ValueError=ValueError,
263 | basestring=basestring,
264 | dict=dict,
265 | float=float,
266 | id=id,
267 | int=int,
268 | isinstance=isinstance,
269 | list=list,
270 | long=long,
271 | str=str,
272 | tuple=tuple,
273 | ):
274 |
275 | def _iterencode_list(lst, _current_indent_level):
276 | if not lst:
277 | yield '[]'
278 | return
279 | if markers is not None:
280 | markerid = id(lst)
281 | if markerid in markers:
282 | raise ValueError("Circular reference detected")
283 | markers[markerid] = lst
284 | buf = '['
285 | if _indent is not None:
286 | _current_indent_level += 1
287 | newline_indent = '\n' + (' ' * (_indent * _current_indent_level))
288 | separator = _item_separator + newline_indent
289 | buf += newline_indent
290 | else:
291 | newline_indent = None
292 | separator = _item_separator
293 | first = True
294 | for value in lst:
295 | if first:
296 | first = False
297 | else:
298 | buf = separator
299 | if isinstance(value, basestring):
300 | yield buf + _encoder(value)
301 | elif value is None:
302 | yield buf + 'null'
303 | elif value is True:
304 | yield buf + 'true'
305 | elif value is False:
306 | yield buf + 'false'
307 | elif isinstance(value, (int, long)):
308 | yield buf + str(value)
309 | elif isinstance(value, float):
310 | yield buf + _floatstr(value)
311 | else:
312 | yield buf
313 | if isinstance(value, (list, tuple)):
314 | chunks = _iterencode_list(value, _current_indent_level)
315 | elif isinstance(value, dict):
316 | chunks = _iterencode_dict(value, _current_indent_level)
317 | else:
318 | chunks = _iterencode(value, _current_indent_level)
319 | for chunk in chunks:
320 | yield chunk
321 | if newline_indent is not None:
322 | _current_indent_level -= 1
323 | yield '\n' + (' ' * (_indent * _current_indent_level))
324 | yield ']'
325 | if markers is not None:
326 | del markers[markerid]
327 |
328 | def _iterencode_dict(dct, _current_indent_level):
329 | if not dct:
330 | yield '{}'
331 | return
332 | if markers is not None:
333 | markerid = id(dct)
334 | if markerid in markers:
335 | raise ValueError("Circular reference detected")
336 | markers[markerid] = dct
337 | yield '{'
338 | if _indent is not None:
339 | _current_indent_level += 1
340 | newline_indent = '\n' + (' ' * (_indent * _current_indent_level))
341 | item_separator = _item_separator + newline_indent
342 | yield newline_indent
343 | else:
344 | newline_indent = None
345 | item_separator = _item_separator
346 | first = True
347 | if _sort_keys:
348 | items = dct.items()
349 | items.sort(key=lambda kv: kv[0])
350 | else:
351 | items = dct.iteritems()
352 | for key, value in items:
353 | if isinstance(key, basestring):
354 | pass
355 | # JavaScript is weakly typed for these, so it makes sense to
356 | # also allow them. Many encoders seem to do something like this.
357 | elif isinstance(key, float):
358 | key = _floatstr(key)
359 | elif isinstance(key, (int, long)):
360 | key = str(key)
361 | elif key is True:
362 | key = 'true'
363 | elif key is False:
364 | key = 'false'
365 | elif key is None:
366 | key = 'null'
367 | elif _skipkeys:
368 | continue
369 | else:
370 | raise TypeError("key %r is not a string" % (key,))
371 | if first:
372 | first = False
373 | else:
374 | yield item_separator
375 | yield _encoder(key)
376 | yield _key_separator
377 | if isinstance(value, basestring):
378 | yield _encoder(value)
379 | elif value is None:
380 | yield 'null'
381 | elif value is True:
382 | yield 'true'
383 | elif value is False:
384 | yield 'false'
385 | elif isinstance(value, (int, long)):
386 | yield str(value)
387 | elif isinstance(value, float):
388 | yield _floatstr(value)
389 | else:
390 | if isinstance(value, (list, tuple)):
391 | chunks = _iterencode_list(value, _current_indent_level)
392 | elif isinstance(value, dict):
393 | chunks = _iterencode_dict(value, _current_indent_level)
394 | else:
395 | chunks = _iterencode(value, _current_indent_level)
396 | for chunk in chunks:
397 | yield chunk
398 | if newline_indent is not None:
399 | _current_indent_level -= 1
400 | yield '\n' + (' ' * (_indent * _current_indent_level))
401 | yield '}'
402 | if markers is not None:
403 | del markers[markerid]
404 |
405 | def _iterencode(o, _current_indent_level):
406 | if isinstance(o, basestring):
407 | yield _encoder(o)
408 | elif o is None:
409 | yield 'null'
410 | elif o is True:
411 | yield 'true'
412 | elif o is False:
413 | yield 'false'
414 | elif isinstance(o, (int, long)):
415 | yield str(o)
416 | elif isinstance(o, float):
417 | yield _floatstr(o)
418 | elif isinstance(o, (list, tuple)):
419 | for chunk in _iterencode_list(o, _current_indent_level):
420 | yield chunk
421 | elif isinstance(o, dict):
422 | for chunk in _iterencode_dict(o, _current_indent_level):
423 | yield chunk
424 | else:
425 | if markers is not None:
426 | markerid = id(o)
427 | if markerid in markers:
428 | raise ValueError("Circular reference detected")
429 | markers[markerid] = o
430 | o = _default(o)
431 | for chunk in _iterencode(o, _current_indent_level):
432 | yield chunk
433 | if markers is not None:
434 | del markers[markerid]
435 |
436 | return _iterencode
437 |
--------------------------------------------------------------------------------
/xbmc-vk.svoka.com/simplejson/scanner.py:
--------------------------------------------------------------------------------
1 | """JSON token scanner
2 | """
3 | import re
4 | try:
5 | from simplejson._speedups import make_scanner as c_make_scanner
6 | except ImportError:
7 | c_make_scanner = None
8 |
9 | __all__ = ['make_scanner']
10 |
11 | NUMBER_RE = re.compile(
12 | r'(-?(?:0|[1-9]\d*))(\.\d+)?([eE][-+]?\d+)?',
13 | (re.VERBOSE | re.MULTILINE | re.DOTALL))
14 |
15 | def py_make_scanner(context):
16 | parse_object = context.parse_object
17 | parse_array = context.parse_array
18 | parse_string = context.parse_string
19 | match_number = NUMBER_RE.match
20 | encoding = context.encoding
21 | strict = context.strict
22 | parse_float = context.parse_float
23 | parse_int = context.parse_int
24 | parse_constant = context.parse_constant
25 | object_hook = context.object_hook
26 |
27 | def _scan_once(string, idx):
28 | try:
29 | nextchar = string[idx]
30 | except IndexError:
31 | raise StopIteration
32 |
33 | if nextchar == '"':
34 | return parse_string(string, idx + 1, encoding, strict)
35 | elif nextchar == '{':
36 | return parse_object((string, idx + 1), encoding, strict, _scan_once, object_hook)
37 | elif nextchar == '[':
38 | return parse_array((string, idx + 1), _scan_once)
39 | elif nextchar == 'n' and string[idx:idx + 4] == 'null':
40 | return None, idx + 4
41 | elif nextchar == 't' and string[idx:idx + 4] == 'true':
42 | return True, idx + 4
43 | elif nextchar == 'f' and string[idx:idx + 5] == 'false':
44 | return False, idx + 5
45 |
46 | m = match_number(string, idx)
47 | if m is not None:
48 | integer, frac, exp = m.groups()
49 | if frac or exp:
50 | res = parse_float(integer + (frac or '') + (exp or ''))
51 | else:
52 | res = parse_int(integer)
53 | return res, m.end()
54 | elif nextchar == 'N' and string[idx:idx + 3] == 'NaN':
55 | return parse_constant('NaN'), idx + 3
56 | elif nextchar == 'I' and string[idx:idx + 8] == 'Infinity':
57 | return parse_constant('Infinity'), idx + 8
58 | elif nextchar == '-' and string[idx:idx + 9] == '-Infinity':
59 | return parse_constant('-Infinity'), idx + 9
60 | else:
61 | raise StopIteration
62 |
63 | return _scan_once
64 |
65 | make_scanner = c_make_scanner or py_make_scanner
66 |
--------------------------------------------------------------------------------
/xbmc-vk.svoka.com/simplejson/tool.py:
--------------------------------------------------------------------------------
1 | r"""Using simplejson from the shell to validate and
2 | pretty-print::
3 |
4 | $ echo '{"json":"obj"}' | python -msimplejson.tool
5 | {
6 | "json": "obj"
7 | }
8 | $ echo '{ 1.2:3.4}' | python -msimplejson.tool
9 | Expecting property name: line 1 column 2 (char 2)
10 | """
11 | import simplejson
12 |
13 | def main():
14 | import sys
15 | if len(sys.argv) == 1:
16 | infile = sys.stdin
17 | outfile = sys.stdout
18 | elif len(sys.argv) == 2:
19 | infile = open(sys.argv[1], 'rb')
20 | outfile = sys.stdout
21 | elif len(sys.argv) == 3:
22 | infile = open(sys.argv[1], 'rb')
23 | outfile = open(sys.argv[2], 'wb')
24 | else:
25 | raise SystemExit("%s [infile [outfile]]" % (sys.argv[0],))
26 | try:
27 | obj = simplejson.load(infile)
28 | except ValueError, e:
29 | raise SystemExit(e)
30 | simplejson.dump(obj, outfile, sort_keys=True, indent=4)
31 | outfile.write('\n')
32 |
33 |
34 | if __name__ == '__main__':
35 | main()
36 |
--------------------------------------------------------------------------------
/xbmc-vk.svoka.com/vk_auth.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: UTF-8 -*-
3 |
4 | import urllib
5 |
6 | try:
7 | import json
8 | except ImportError:
9 | import simplejson as json
10 |
11 |
12 | def auth(email, password, client_id, secret,scope,code):
13 | if code == "0":
14 | try:
15 | url = urllib.urlopen("https://oauth.vk.com/token?" + urllib.urlencode({
16 | "grant_type": "password",
17 | "client_id": client_id,
18 | "client_secret": secret,
19 | "username": email,
20 | "password": password,
21 | "scope": scope,
22 | "2fa_supported": "1"
23 | }))
24 |
25 | out = json.load(url)
26 |
27 | except IOError as e:
28 | print(e.message)
29 | print("===VK 2FA Code requested===")
30 | return "-1"
31 | else:
32 | url = urllib.urlopen("https://oauth.vk.com/token?" + urllib.urlencode({
33 | "grant_type": "password",
34 | "client_id": client_id,
35 | "client_secret": secret,
36 | "username": email,
37 | "password": password,
38 | "scope": scope,
39 | "2fa_supported": "1",
40 | "code": code
41 | }))
42 |
43 | out = json.load(url)
44 |
45 | if "access_token" not in out:
46 | print out
47 | return out["access_token"]
48 |
--------------------------------------------------------------------------------
/xbmc-vk.svoka.com/vkapicaller.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | # VK-XBMC add-on
4 | # Copyright (C) 2011 Volodymyr Shcherban
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | __author__ = 'Volodymyr Shcherban'
19 |
20 | import urllib
21 | try:
22 | import json
23 | except ImportError:
24 | import simplejson as json
25 |
26 | try:
27 | from hashlib import md5
28 | except ImportError:
29 | from md5 import md5
30 |
31 |
32 | def ApiFromToken(token):
33 | return VkApp(token)
34 |
35 |
36 | class VkApp:
37 | def __init__(self, access_token):
38 | #param is API call parameters
39 | if not access_token:
40 | raise Exception("Trying to create API without token")
41 | self.param = {'access_token': access_token}
42 |
43 | def call(self, api, **call_params):
44 | v = dict()
45 | v.update(self.param)
46 | v.update(call_params)
47 |
48 | request = "&".join(["%s=%s" % (str(key), urllib.quote(str(v[key]))) for key in v.keys()])
49 | request_url = "https://api.vk.com/method/" + api + "?" + request
50 |
51 | reply = urllib.urlopen(request_url)
52 | resp = json.load(reply)
53 | if "error" in resp:
54 | raise Exception("Error, error! DATA: " + str(resp))
55 | else:
56 | return resp["response"]
57 |
--------------------------------------------------------------------------------
/xbmc-vk.svoka.com/vkapp.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | # VK-XBMC add-on
4 | # Copyright (C) 2011 Volodymyr Shcherban
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | __author__ = 'Volodymyr Shcherban'
19 |
20 | from vk_auth import auth
21 | import xbmcaddon
22 | import xbmc
23 |
24 |
25 | __settings__ = xbmcaddon.Addon(id='xbmc-vk.svoka.com')
26 | __language__ = __settings__.getLocalizedString
27 |
28 |
29 | APP_ID = "2054573"
30 |
31 |
32 | from vkapicaller import ApiFromToken
33 |
34 |
35 | class XBMCVkAppCreator:
36 | def __init__(self):
37 | self.instance = None
38 |
39 | def GetInstance(self):
40 | return self.instance or self.NewInstance()
41 |
42 | def NewInstance(self):
43 | token = __settings__.getSetting('auth_token')
44 | if len(token or "") < 5:
45 | token = self._requestToken()
46 | self.instance = ApiFromToken(token)
47 | return self.instance
48 |
49 | def _requestToken(self):
50 | token = None
51 | count = 5
52 | while not token and count > 0:
53 | count -= 1
54 | login, password = self._askLogin()
55 | token = auth(login, password, APP_ID, "KUPNPTTQGApLFVOVgqdx", 'friends,groups,photos,audio,video,offline',"0")
56 | if token == "-1":
57 | code = self._askCode()
58 | token = auth(login, password, APP_ID, "KUPNPTTQGApLFVOVgqdx", 'friends,groups,photos,audio,video,offline',code)
59 | if token:
60 | __settings__.setSetting('auth_token', token)
61 | return token
62 |
63 | def _askLogin(self):
64 | user_keyboard = xbmc.Keyboard()
65 | user_keyboard.setHeading(__language__(30001))
66 | user_keyboard.setHiddenInput(False)
67 | user_keyboard.setDefault(__settings__.getSetting('username'))
68 | user_keyboard.doModal()
69 | if user_keyboard.isConfirmed():
70 | username = user_keyboard.getText()
71 | pass_keyboard = xbmc.Keyboard()
72 | pass_keyboard.setHeading(__language__(30002))
73 | pass_keyboard.setHiddenInput(True)
74 | pass_keyboard.doModal()
75 | if pass_keyboard.isConfirmed():
76 | return username, pass_keyboard.getText()
77 | else:
78 | raise Exception("Password input was cancelled.")
79 | else:
80 | raise Exception("Login input was cancelled.")
81 |
82 | def _askCode(self):
83 | code_keyboard = xbmc.Keyboard()
84 | code_keyboard.setHeading(__language__(30050))
85 | code_keyboard.setHiddenInput(False)
86 | code_keyboard.doModal()
87 | if code_keyboard.isConfirmed():
88 | return code_keyboard.getText()
89 | else:
90 | raise Exception("2FA Code input was cancelled")
91 |
92 |
93 | appManager = XBMCVkAppCreator()
94 |
95 |
96 | def GetApi():
97 | return appManager.GetInstance()
98 |
--------------------------------------------------------------------------------
/xbmc-vk.svoka.com/vkcookie.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | # VK-XBMC add-on
4 | # Copyright (C) 2011 Volodymyr Shcherban
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | __author__ = 'Volodymyr Shcherban'
19 |
20 | import sys,urllib, urllib2, cookielib, re, string, xbmc #, xbmcaddon, xbmc, xbmcgui, xbmcplugin, os
21 |
22 | def GetCookie(mail,passw):
23 | host = 'https://login.vk.com/'
24 | post = urllib.urlencode({
25 | 'act':'login',
26 | 'q':'1',
27 | 'al_frame':'1',
28 | 'expire':'',
29 | 'captcha_sid':'',
30 | 'captcha_key':'',
31 | 'from_host':'vk.com',
32 | 'email':mail,
33 | 'pass': passw
34 | })
35 |
36 | headers = {
37 | 'Referer': 'http://vk.com/al_index.php?act=auth_frame',
38 | 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.803.0 Safari/535.1',
39 | 'Content-Type': 'application/x-www-form-urlencoded',
40 | }
41 | conn = urllib2.Request(host, post, headers)
42 | data = urllib2.urlopen(conn)
43 | i = data.info()
44 |
45 | #xbmc.log(str(i))
46 | cookie = re.findall(r'remixsid=(.*?);', str(i))[0]
47 | #xbmc.log("Cookie is " + cookie)
48 | if not cookie or cookie == 'deleted':
49 | raise Exception("Wrong login!")
50 | #xbmc.log("koka " + cookie)
51 | return cookie
52 |
53 |
54 | class VkontakteCookie:
55 | def __init__(self, email, password):
56 | self.email = email
57 | self.password = password
58 | self.cookie = None
59 |
60 | def get_s_value(self):
61 | #Возвращает уникальный идентификатор, который выдается на домене login.vk.com
62 | host = 'http://login.vk.com/'
63 | post = urllib.urlencode({'email' : self.email,
64 | 'expire' : '',
65 | 'pass' : self.password,
66 | 'q' : '1',
67 | 'act' :'login', 'al_frame' : '1', 'captcha_sid' : '', 'captcha_key' : '',
68 | 'from_host':'vk.com'})
69 |
70 | headers = {'User-Agent' : 'Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.13) Gecko/2009073022 Firefox/3.0.13',
71 | 'Host' : 'login.vk.com',
72 | 'Referer' : 'http://vk.com/',
73 | 'Origin' : 'http://vk.com/',
74 | 'Connection' : 'close',
75 | 'Pragma' : 'no-cache',
76 | 'Cache-Control' : 'no-cache'
77 | }
78 |
79 | conn = urllib2.Request(host, post, headers)
80 | data = urllib2.urlopen(conn)
81 | ssv = data.read()
82 | return re.findall(r"name='s' value='(.*?)'", ssv)[0]
83 |
84 | def get_cookie(self):
85 | #Возвращает remixsid из куки
86 | if self.cookie: return self.cookie
87 |
88 | host = 'http://vkontakte.ru/login.php?op=slogin'
89 | post = urllib.urlencode({'s' : self.get_s_value()})
90 | headers = {'User-Agent' : 'Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.13) Gecko/2009073022 Firefox/3.0.13',
91 | 'Host' : 'vkontakte.ru',
92 | 'Referer' : 'http://login.vk.com/?act=login',
93 | 'Connection' : 'close',
94 | 'Cookie' : 'remixchk=5; remixsid=nonenone',
95 | 'Pragma' : 'no-cache',
96 | 'Cache-Control' : 'no-cache'
97 | }
98 | conn = urllib2.Request(host, post, headers)
99 | data = urllib2.urlopen(conn)
100 | cookie_src = data.info().get('Set-Cookie')
101 | cooke_str = re.sub(r'(expires=.*?;\s|path=\/;\s|domain=\.vkontakte\.ru(?:,\s)?)', '', cookie_src)
102 | self.cookie = cooke_str.split("=")[-1].split(";")[0].strip()
103 | if not self.cookie:
104 | raise Exception('Wrong login')
105 | return self.cookie
106 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/xbmc-vk.svoka.com/vkparsers.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | # VK-XBMC add-on
4 | # Copyright (C) 2011 Volodymyr Shcherban
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | __author__ = 'Volodymyr Shcherban'
19 |
20 | import urllib, urllib2, re, cookielib, base64
21 | import vkapp
22 |
23 | try:
24 | import json
25 | except ImportError:
26 | import simplejson as json
27 |
28 | def GetVideoFilesAPI(codedFiles):
29 | files = json.loads(base64.decodestring(codedFiles))
30 | external_url = files.get("external")
31 | if external_url:
32 | if "youtube" in external_url:
33 | start = external_url.find("v=") + len('v=')
34 | end = external_url.find('&', start)
35 | if start <= len('embed/'):
36 | return [external_url]
37 | if end < 0:
38 | end = None
39 | return ["plugin://plugin.video.youtube/?action=play_video&videoid="+external_url[start:end]]
40 | return [external_url]
41 | ret = []
42 | for v in files:
43 | ret.append(files[v])
44 | return ret
45 |
46 |
47 | def GetVideoFiles(url):
48 | app = vkapp.appManager
49 | # TODO make this a generic function in appManager
50 | proc = urllib2.HTTPCookieProcessor()
51 | proc.cookiejar.set_cookie(cookielib.Cookie(0, 'remixsid', app.GetCookie(),
52 | '80', False, 'vk.com', True, False, '/',
53 | True, False, None, False, None, None, None))
54 | opener = urllib2.build_opener(urllib2.HTTPHandler(), proc)
55 | html = opener.open(url).read()
56 |
57 | player = re.findall(r"\\nvar vars =(.*?});", html)
58 | if not player:
59 | yt = re.findall(r"www\.youtube\.com\\/embed\\/(.*?)\?autoplay",html)
60 | if not yt:
61 | return ["/unable to play " + url]
62 | return ["plugin://plugin.video.youtube/?action=play_video&videoid="+str(yt[0])]
63 | tmp = ""
64 | for a in player[0]:
65 | if ord(a)< 128:
66 | tmp += a
67 | else:
68 | tmp += urllib.quote(a)
69 | player[0] = filter(lambda x: x != "\\", tmp)
70 |
71 | jsonStr = player[0]
72 | prs = json.loads(jsonStr)
73 |
74 | urlStart = "http://cs" + str(prs["host"]) + ".vk.com/u" + str(prs["uid"]) + "/videos/" + str(prs["vtag"])
75 |
76 | resolutions = ["240", "360", "480", "720", "1080"]
77 | videoURLs = []
78 | if prs["no_flv"]!=1:
79 | if str(prs["uid"])=="0": #strange behaviour on old videos
80 | urlStart = "http://" + prs["host"] + "/assets/videos/" + str(prs["vtag"]) + str(prs["vkid"]) + ".vk"
81 | videoURLs.append(urlStart + ".flv")
82 |
83 | if prs["hd"]>0 or prs["no_flv"]==1:
84 | for i in range(int(prs["hd"])+1):
85 | videoURLs.append(urlStart + "." + resolutions[i] + ".mp4")
86 |
87 | videoURLs.reverse()
88 | return videoURLs
89 |
90 | if __name__== '__main__':
91 | import sys
92 | if len(sys.argv) > 1:
93 | try:
94 | url = "http://vk.com/" + re.findall(r"(video[-0-9]+[-_][0-9]+)", sys.argv[1])[0]
95 | print url
96 | for s in GetVideoFiles(url):
97 | print s
98 | except Exception, e:
99 | sys.stderr.writelines(["error: " + str(e) + "\n", "usage: vkparsers.py http://vk.com/video111_222\n"])
100 | else:
101 | print("usage: vkparsers.py http://vk.com/video111_222")
102 |
--------------------------------------------------------------------------------
/xbmc-vk.svoka.com/xbmcvkui.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | # VK-XBMC add-on
4 | # Copyright (C) 2011 Volodymyr Shcherban
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | from xml.sax.saxutils import unescape
19 |
20 | __author__ = 'Volodymyr Shcherban'
21 |
22 | import xbmcplugin, urllib, sys, os
23 |
24 | PLUGIN_NAME = 'VK-xbmc'
25 |
26 | HOME = 'HOME'
27 | FRIENDS = "FRIENDS"
28 | FRIEND_ENTRY = "FRIEND_ENTRY"
29 |
30 |
31 | def PrepareString(str):
32 | return unescape(str, {"'": "'", "'" : "'", "'" : "'", """: '"'})
33 |
34 |
35 | class XBMCVkUI_Base:
36 | def __init__(self, parameters, handle, api):
37 | self.api = api
38 | self.handle = handle
39 | self.params = parameters
40 | self.Populate(getattr(self, "Do_" + self.params["mode"], self.Do_HOME))
41 |
42 | def Populate(self, content):
43 | self.PrefixActions()
44 | content()
45 | xbmcplugin.setPluginCategory(self.handle, PLUGIN_NAME)
46 | xbmcplugin.endOfDirectory(self.handle)
47 |
48 | def PrefixActions(self):
49 | pass
50 |
51 | def Do_HOME(self):
52 | pass
53 |
54 | def GetURL(self, __dict_params=dict(), **parameters):
55 | #UNOCODE things here???
56 | __dict_params.update(parameters)
57 | return sys.argv[0] + "?" + urllib.urlencode(__dict_params)
58 |
59 | def friendsEntry(self, type):
60 | listItem = xbmcgui.ListItem(xbmcaddon.Addon(id='xbmc-vk.svoka.com').getLocalizedString(30043))
61 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode=FRIENDS, type=type), listItem, True)
62 |
63 | def Do_FRIENDS(self):
64 | type = self.params["type"]
65 |
66 | #we have 'music', 'video', 'image'
67 | call_params={"fields": 'uid,first_name,last_name,photo_big,nickname', "order": 'hints', "v": "5.7"}
68 | if type == 'music':
69 | call_params["fields"] += ",can_see_audio"
70 | resp = self.api.call('friends.get', **call_params)
71 |
72 | friends = resp['items']
73 | for friend in friends:
74 | if 'deactivated' in friend:
75 | continue
76 | if type == 'music' and not friend.get('can_see_audio'):
77 | continue
78 | name = "%s %s" % (friend.get('last_name'), friend.get('first_name'))
79 | if friend.get('nickname'):
80 | name += " " + friend.get('nickname')
81 | listItem = xbmcgui.ListItem(name, "", friend['photo_big'])
82 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode=FRIEND_ENTRY, uid=friend['id'], thumb=friend['photo_big']), listItem, True)
83 |
84 | def Do_FRIEND_ENTRY(self):
85 | uid = self.params["uid"]
86 | self.processFriendEntry(uid)
87 |
88 | def processFriendEntry(self, uid):
89 | pass
90 |
91 | def Do_LOGOUT(self):
92 | __settings__.setSetting('auth_token', "")
93 | __settings__.setSetting('username', "")
94 |
95 |
96 |
97 | import xbmc,xbmcaddon, xbmcgui
98 |
99 | saved_search_file = os.path.join(xbmc.translatePath('special://temp/').decode('utf-8'), u'vk-search%s.sess')
100 | __settings__ = xbmcaddon.Addon(id='xbmc-vk.svoka.com')
101 | SEARCH, SEARCH_HISTORY = "SEARCH,SEARCH_HISTORY".split(",")
102 |
103 |
104 |
105 | class XBMCVkUI_Search_Base(XBMCVkUI_Base):
106 | def PrefixActions(self):
107 | listItem = xbmcgui.ListItem(self.locale["newSearch"]) #new search - always first element
108 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode=SEARCH) , listItem, True)
109 |
110 | def Do_HOME(self):
111 | if self.GetSearchHistory(self.histId):
112 | listItem = xbmcgui.ListItem(self.locale["history"]) #search history
113 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode=SEARCH_HISTORY) , listItem, True)
114 |
115 |
116 | def Do_SEARCH(self):
117 | query = self.params.get("query")
118 | if not query:
119 | kb = xbmc.Keyboard()
120 | kb.setHiddenInput(False)
121 | kb.setHeading(self.locale["input"])
122 | history = self.GetSearchHistory(self.histId)
123 | if history:
124 | kb.setDefault(history[0])
125 | kb.doModal()
126 | if kb.isConfirmed():
127 | query = kb.getText()
128 | self.params["query"] = query
129 | self.Search(query)
130 |
131 |
132 | def Do_SEARCH_HISTORY(self):
133 | history = self.GetSearchHistory(self.histId)
134 | if history:
135 | for q in history:
136 | listItem = xbmcgui.ListItem(PrepareString(q))
137 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode=SEARCH,query=q), listItem, True)
138 |
139 |
140 | def GetSearchHistory(self, searchId = None):
141 | history = []
142 | if os.path.isfile(saved_search_file % unicode(searchId)):
143 | fl = open(saved_search_file % unicode(searchId),"r")
144 | history = fl.readlines()
145 | history = map(lambda s: s.strip(), history)
146 | history = filter(None, history)
147 | fl.close()
148 | return history
149 |
150 | def AddSearchHistory(self, query, searchId = None):
151 | query = query.strip()
152 | if not query:
153 | return
154 | max = int(__settings__.getSetting('history'))
155 | max = [5, 10, 15, 20, 25, 30, 40, 50, 75, 100][max]
156 | lines = []
157 | if os.path.isfile(saved_search_file % unicode(searchId)):
158 | fl = open(saved_search_file % unicode(searchId),"r")
159 | lines = fl.readlines()
160 | fl.close()
161 | lines = map(lambda s: s.strip(), lines)
162 | lines = filter(None, lines)
163 | while query in lines: #could replace with `if`, nothing should change...
164 | lines.remove(query)
165 | lines.insert(0, query)
166 | fl = open(saved_search_file % unicode(searchId), "w")
167 | fl.write("\n".join(lines[:max]))
168 | fl.close()
169 |
170 |
171 |
172 | class XBMCVkUI_VKSearch_Base(XBMCVkUI_Search_Base):
173 | def __init__(self, *params):
174 | self.searchTweaks = {"count" : "25"}
175 | XBMCVkUI_Search_Base.__init__(self, *params)
176 |
177 |
178 | def Search(self,query):
179 | result = None
180 | if query:
181 | self.AddSearchHistory(query, self.histId)
182 | self.searchTweaks["q"]=query
183 | self.DoSearchTweaks()
184 | result = self.api.call(self.apiName, **self.searchTweaks)
185 | result = self.transformResult(result)
186 | if result:
187 | for a in result:
188 | self.ProcessFoundEntry(a)
189 |
190 | def transformResult(self, res):
191 | return res
192 |
193 | def DoSearchTweaks(self):
194 | pass
195 |
--------------------------------------------------------------------------------
/xbmc-vk.svoka.com/xvaudio.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | # VK-XBMC add-on
4 | # Copyright (C) 2011 Volodymyr Shcherban
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | __author__ = 'Volodymyr Shcherban'
19 |
20 | import urllib
21 |
22 |
23 |
24 | __author__ = 'vova'
25 |
26 | import xbmcgui, xbmc, xbmcplugin, xbmcaddon, datetime, os
27 |
28 | from xbmcvkui import XBMCVkUI_VKSearch_Base,SEARCH, PrepareString
29 | import datetime
30 |
31 | __settings__ = xbmcaddon.Addon(id='xbmc-vk.svoka.com')
32 | __language__ = __settings__.getLocalizedString
33 | saved_search_file = os.path.join(xbmc.translatePath('special://temp/').decode('utf-8'), u'vk-search.sess')
34 |
35 | #modes
36 | ALBUM,MY_MUSIC,HYPED_ARTISTS,RECOMENDED_MUSIC,POPULAR_MUSIC = "ALBUM,MY_MUSIC,HYPED_ARTISTS,RECOMENDED_MUSIC,POPULAR_MUSIC".split(',')
37 |
38 | from xml.dom import minidom
39 |
40 | class XVKAudio(XBMCVkUI_VKSearch_Base):
41 | def __init__(self, *params):
42 | self.histId = "Audio"
43 | self.apiName = "audio.search"
44 | self.locale = {"newSearch":__language__(30008), "history": __language__(30007), "input":__language__(30003)}
45 | XBMCVkUI_VKSearch_Base.__init__(self, *params)
46 |
47 | def Do_HOME(self):
48 | XBMCVkUI_VKSearch_Base.Do_HOME(self)
49 | listItem = xbmcgui.ListItem(__language__(30009))
50 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode=MY_MUSIC) , listItem, True)
51 | listItem = xbmcgui.ListItem(__language__(30016))
52 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode=HYPED_ARTISTS) , listItem, True)
53 | listItem = xbmcgui.ListItem(__language__(30023))
54 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode=RECOMENDED_MUSIC) , listItem, True)
55 | listItem = xbmcgui.ListItem(__language__(30024))
56 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode=POPULAR_MUSIC) , listItem, True)
57 | self.friendsEntry("music")
58 | listItem = xbmcgui.ListItem(__language__(30020))
59 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode="LOGOUT"), listItem, True)
60 |
61 | def processFriendEntry(self, uid):
62 | for a in self.api.call("audio.get", uid=uid):
63 | self.AddAudioEntry(a)
64 |
65 |
66 | def Do_HYPED_ARTISTS(self):
67 | srl = minidom.parse(urllib.urlopen("http://ws.audioscrobbler.com/2.0/?method=chart.gethypedartists&api_key=42db3eb160b603b55f8886e8c4e9a8f4"))
68 | artists = srl.getElementsByTagName("artist")
69 | for a in artists:
70 | thumb =""
71 | thumbNode = a.getElementsByTagName("image")[2].childNodes
72 | if thumbNode:
73 | thumb = thumbNode[0].nodeValue
74 | name = a.getElementsByTagName("name") [0].childNodes[0].nodeValue
75 | name = name.encode('utf-8')
76 | listItem = xbmcgui.ListItem(name, "", thumb, thumb)
77 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode=SEARCH, query=name, thumb=thumb) , listItem, True)
78 |
79 |
80 | def transformResult(self,res):
81 | if res and res[0]:
82 | return res[1:]
83 | else:
84 | return []
85 |
86 | def ProcessFoundEntry(self, a):
87 | self.AddAudioEntry(a)
88 |
89 |
90 | def Do_MY_MUSIC(self):
91 | for a in self.api.call("audio.get"):
92 | self.AddAudioEntry(a)
93 |
94 | def Do_RECOMENDED_MUSIC(self):
95 | for a in self.api.call("audio.getRecommendations", count=500):
96 | self.AddAudioEntry(a)
97 |
98 | def Do_POPULAR_MUSIC(self):
99 | for a in self.api.call("audio.getPopular", count=500):
100 | self.AddAudioEntry(a)
101 |
102 | def AddAudioEntry(self, a):
103 | title = a.get("artist")
104 | if title:
105 | title += u" : "
106 | title += a.get("title")
107 | d = unicode(datetime.timedelta(seconds=int(a["duration"])))
108 | listTitle = d + u" - " + title
109 | listitem = xbmcgui.ListItem(PrepareString(listTitle))
110 | xbmc.log(str(a),xbmc.LOGDEBUG)
111 | listitem.setInfo(type='Music', infoLabels={'title': a.get("title") or "",
112 | 'artist': a.get("artist") or "",
113 | 'album': a.get("artist") or "",
114 | 'duration': a.get('duration') or 0})
115 | listitem.setProperty('mimetype', 'audio/mpeg')
116 |
117 | xbmcplugin.addDirectoryItem(self.handle, a["url"], listitem, False)
118 |
--------------------------------------------------------------------------------
/xbmc-vk.svoka.com/xvimage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | # VK-XBMC add-on
4 | # Copyright (C) 2011 Volodymyr Shcherban
5 | #
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | __author__ = 'Volodymyr Shcherban'
19 |
20 |
21 | import xbmcgui, xbmc, xbmcplugin, xbmcaddon, datetime, os
22 |
23 | from xbmcvkui import XBMCVkUI_Base,HOME, PrepareString
24 | from datetime import datetime
25 |
26 | __settings__ = xbmcaddon.Addon(id='xbmc-vk.svoka.com')
27 | __language__ = __settings__.getLocalizedString
28 | saved_search_file = os.path.join(xbmc.translatePath('special://temp/').decode('utf-8'), u'vk-search.sess')
29 |
30 | #modes
31 | ALBUM = "ALBUM"
32 |
33 | class XVKImage(XBMCVkUI_Base):
34 |
35 | def Do_HOME(self):
36 | for title, title2, thumb, id, owner in self.GetAlbums():
37 | listItem = xbmcgui.ListItem(title, title2, thumb, thumb, ) #search history
38 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode=ALBUM, album=id, user=owner) , listItem, True)
39 | self.friendsEntry("image")
40 | listItem = xbmcgui.ListItem(__language__(30020))
41 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode="LOGOUT"), listItem, True)
42 |
43 |
44 |
45 | def Do_ALBUM(self):
46 | album = self.api.call("photos.get", uid = self.params["user"], aid = self.params["album"])
47 | photos = []
48 | for cameo in album:
49 | title = None
50 | if cameo["text"]:
51 | title = cameo["text"] + u" (" + unicode(str(datetime.fromtimestamp(int(cameo["created"])))) + u")"
52 | else:
53 | title = unicode(str(datetime.fromtimestamp(int(cameo["created"]))))
54 | title = PrepareString(title)
55 | e = ( title,
56 | cameo.get("src_xxbig") or cameo.get("src_xbig") or cameo.get("src_big") or cameo["src"],
57 | cameo["src"] )
58 | photos.append(e)
59 | for title, url, thumb in photos:
60 | listItem = xbmcgui.ListItem(title, "", thumb, thumb, ) #search history
61 | xbmcplugin.addDirectoryItem(self.handle, url , listItem, False)
62 |
63 | def processFriendEntry(self, uid):
64 | for title, title2, thumb, id, owner in self.GetAlbums(uid):
65 | listItem = xbmcgui.ListItem(title, title2, thumb, thumb, ) #search history
66 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode=ALBUM, album=id, user=owner) , listItem, True)
67 |
68 | def GetAlbums(self, uid=None):
69 | albums=None
70 | if uid:
71 | albums=self.api.call("photos.getAlbums", need_covers=1, uid=uid)
72 | else:
73 | albums=self.api.call("photos.getAlbums", need_covers=1)
74 | items = []
75 | for a in albums:
76 | xbmc.log(a.get('thumb_src'),xbmc.LOGDEBUG)
77 | e = ( a["title"] + unicode(" (%s photo)" % a["size"]),
78 | a["description"],
79 | a.get('thumb_src'),
80 | str(a["aid"]),
81 | a["owner_id"] )
82 | items.append(e)
83 | return items
84 |
--------------------------------------------------------------------------------
/xbmc-vk.svoka.com/xvvideo.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | # VK-XBMC add-on
4 | # Copyright (C) 2011 Volodymyr Shcherban
5 |
6 | # This program is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This program is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this program. If not, see .
18 | __author__ = 'Volodymyr Shcherban'
19 |
20 |
21 | import xbmcgui, xbmc, xbmcplugin, xbmcaddon, datetime, os, urllib, re, sys
22 | import base64
23 |
24 |
25 | from xml.dom import minidom
26 |
27 | from vkparsers import GetVideoFilesAPI
28 | from xbmcvkui import XBMCVkUI_VKSearch_Base,SEARCH, PrepareString
29 |
30 | try:
31 | import json
32 | except ImportError:
33 | import simplejson as json
34 |
35 |
36 | __settings__ = xbmcaddon.Addon(id='xbmc-vk.svoka.com')
37 | __language__ = __settings__.getLocalizedString
38 |
39 |
40 | SEARCH_RESULT, TOP_DOWNLOADS, SERIES, MY_VIDEOS, SEASONS, SEASON_SERIES = "SEARCH_RESULT,TOP_DOWNLOADS,SERIES,MY_VIDEOS,SEASONS,SEASON_SERIES".split(',')
41 | SEARCH_RESULT_DOWNLOAD = "SEARCH_RESULT_DOWNLOAD"
42 | VIDEO_DOWNLOAD = "VIDEO_DOWNLOAD"
43 | GROUP_VIDEO = "GROUP_VIDEO"
44 | GROUPS = "GROUPS"
45 |
46 | ALBUM_VIDEO = "ALBUM_VIDEO"
47 |
48 |
49 |
50 | class XVKVideo(XBMCVkUI_VKSearch_Base):
51 |
52 | def __init__(self, *params):
53 | self.offset = 0
54 | self.per_page = 50
55 | self.histId = None
56 | self.apiName = "video.search"
57 | self.locale = {"newSearch":__language__(30005), "history": __language__(30007), "input":__language__(30003)}
58 | XBMCVkUI_VKSearch_Base.__init__(self, *params)
59 |
60 | def DoSearchTweaks(self):
61 | if __settings__.getSetting('hdOnly') == 'true' or "hd" in self.params:
62 | self.searchTweaks["hd"] = "1"
63 | else:
64 | listItem = xbmcgui.ListItem(__language__(30019))
65 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode=SEARCH, query=self.searchTweaks["q"], hd = "1") , listItem, True)
66 | if __settings__.getSetting('sortLen') == 'true':
67 | self.searchTweaks["sort"] = "1"
68 | if __settings__.getSetting("SafeSearch") == "false":
69 | self.searchTweaks["adult"] = "1"
70 |
71 | def ProcessFoundEntry(self, a):
72 | duration = str(datetime.timedelta(seconds=int(a["duration"])))
73 | title = duration + " - " + PrepareString(a["title"])
74 | videos = base64.encodestring(json.dumps(a["files"]))
75 | thumb = a.get("thumb") or a.get("image")
76 | listItem = xbmcgui.ListItem(title, a["description"], thumb, thumb)
77 | listItem.setInfo(type = "Video", infoLabels = {
78 | "title" : title
79 | ,"duration" : duration
80 | ,"tagline" : a["description"]
81 | } )
82 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode=SEARCH_RESULT, thumb=thumb, v=videos, title=a["title"].encode('utf-8')),
83 | listItem, True)
84 |
85 | def Do_SEARCH_RESULT(self):
86 | vf = GetVideoFilesAPI(self.params["v"])
87 | if vf:
88 | for a in vf:
89 | n = a[a.rfind("/")+1:]
90 | if a.startswith("http"):
91 | n = __language__(30039) + " " + n
92 | else:
93 | n = "YouTube: " + n
94 | listitem = xbmcgui.ListItem(n, "", self.params.get("thumb"), self.params.get("thumb"), path=a)
95 | listitem.setProperty('IsPlayable', 'true')
96 | listitem.setInfo(type = "video", infoLabels = {'title': self.params.get("title")})
97 | xbmcplugin.addDirectoryItem(self.handle, a, listitem)
98 | if vf and __settings__.getSetting("ShowDownload") == "true":
99 | for a in vf:
100 | if a.startswith("http"):
101 | listitem = xbmcgui.ListItem(__language__(30035) + " " + a[a.rfind("/")+1:], "", self.params.get("thumb"), self.params.get("thumb"))
102 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode=VIDEO_DOWNLOAD, thumb=self.params.get("thumb"), v=base64.encodestring(a).strip()), listitem, False)
103 |
104 | def Do_SEARCH_RESULT_DOWNLOAD(self):
105 | vf = GetVideoFilesAPI(self.params["v"])
106 | if vf:
107 | for a in vf:
108 | listitem = xbmcgui.ListItem(__language__(30035) + " " + a[a.rfind("/")+1:], "", self.params.get("thumb"), self.params.get("thumb"))
109 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode=VIDEO_DOWNLOAD, thumb=self.params.get("thumb"), v=base64.encodestring(a).strip()), listitem, True)
110 |
111 | def Do_VIDEO_DOWNLOAD(self):
112 | downloadCmd = __settings__.getSetting("downloadCmd")
113 | url = base64.decodestring(self.params["v"])
114 | if not downloadCmd:
115 | if xbmc.getCondVisibility("system.platform.android"):
116 | cmd = 'StartAndroidActivity("", "android.intent.action.VIEW", "", "%s")' % ( url )
117 | xbmc.executebuiltin(cmd)
118 | elif xbmc.getCondVisibility("system.platform.windows"):
119 | downloadCmd = "start"
120 | else:
121 | downloadCmd = "open"
122 |
123 | if downloadCmd:
124 | __settings__.setSetting("downloadCmd", downloadCmd)
125 | if '{url}' in downloadCmd:
126 | os.system(downloadCmd.replace('{url}', url))
127 | else:
128 | os.system(downloadCmd + " " + url)
129 |
130 |
131 | def Do_HOME(self):
132 | XBMCVkUI_VKSearch_Base.Do_HOME(self)
133 | listItem = xbmcgui.ListItem(__language__(30010))
134 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode=TOP_DOWNLOADS), listItem, True)
135 | listItem = xbmcgui.ListItem(__language__(30011))
136 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode=SERIES), listItem, True)
137 | listItem = xbmcgui.ListItem(__language__(30012))
138 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode=MY_VIDEOS), listItem, True)
139 | listItem = xbmcgui.ListItem(__language__(30042))
140 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode=GROUPS), listItem, True)
141 |
142 | self.friendsEntry("video")
143 |
144 | listItem = xbmcgui.ListItem(__language__(30020))
145 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode="LOGOUT"), listItem, True)
146 |
147 |
148 | def prevPage(self, **params):
149 | self.offset = int(self.params.get("offset") or 0)
150 | if self.offset:
151 | listItem = xbmcgui.ListItem(__language__(30046)%(self.offset/self.per_page))
152 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode=self.params["mode"], offset=self.offset-self.per_page, **params), listItem, True)
153 | listItem = xbmcgui.ListItem(__language__(30021))
154 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode="HOME"), listItem, True)
155 |
156 |
157 | def nextPage(self, v, **params):
158 | if v:
159 | if int(v[0]) >= self.offset+self.per_page:
160 | listItem = xbmcgui.ListItem(__language__(30044)%(1+self.offset/self.per_page))
161 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode=self.params["mode"], offset=self.offset+self.per_page, **params), listItem, True)
162 |
163 |
164 | def Do_GROUP_VIDEO(self):
165 | gid = self.params["gid"]
166 | self.prevPage(gid=gid)
167 |
168 | listItem = xbmcgui.ListItem(__language__(40002))
169 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode=ALBUM_VIDEO, owner_id="-"+gid), listItem, True)
170 |
171 | v = self.api.call('video.get', gid=gid, count=self.per_page, offset=self.offset)
172 | if v:
173 | for a in v[1:]:
174 | self.ProcessFoundEntry(a)
175 | self.nextPage(v,gid=gid)
176 |
177 |
178 | def processFriendEntry(self, uid):
179 | self.prevPage(uid=uid)
180 |
181 | listItem = xbmcgui.ListItem(__language__(40002))
182 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode=ALBUM_VIDEO, owner_id=uid), listItem, True)
183 |
184 | v = self.api.call('video.get', uid=uid, count=self.per_page, offset=self.offset)
185 | if v:
186 | for a in v[1:]:
187 | self.ProcessFoundEntry(a)
188 | self.nextPage(v,uid=uid)
189 |
190 | def Do_GROUPS(self):
191 | resp = self.api.call('groups.get',extended=1)
192 | groups = resp[1:]
193 | for group in groups:
194 | listItem = xbmcgui.ListItem(group['name'], "", group['photo_big'])
195 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode=GROUP_VIDEO, gid=group['gid'], thumb=group['photo_medium']) , listItem, True)
196 |
197 |
198 | def Do_SERIES(self):
199 | series = json.load(urllib.urlopen("http://api.myshows.ru/shows/top/all/"))
200 | for s in series:
201 | thumb = s.get('image') or ""
202 | names = (PrepareString(s.get('title') or ""), PrepareString(s.get('ruTitle') or ""))
203 | if all(names):
204 | listItem = xbmcgui.ListItem(" / ".join(names), str(s.get('year') or ""), thumb, thumb)
205 | else:
206 | listItem = xbmcgui.ListItem(names[0] or names[1], str(s.get('year') or ""), thumb, thumb)
207 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode=SEASON_SERIES, id=s['id']), listItem, True)
208 |
209 |
210 | def Do_SEASON_SERIES(self):
211 | show = json.load(urllib.urlopen("http://api.myshows.ru/shows/" + self.params["id"]))
212 | film = PrepareString(show.get('ruTitle') or "") or PrepareString(show.get('title') or "")
213 | episodes = show['episodes']
214 | thumb = show.get('image')
215 | srt = []
216 | for eid in episodes:
217 | e = episodes[eid]
218 | title = e["title"]
219 | desc = e["airDate"] or ""
220 | title = __language__(30014) % (e['seasonNumber'], e['episodeNumber']) + (title and (u": " + title))
221 | et = e.get('image') or thumb
222 | listItem = xbmcgui.ListItem(PrepareString(title), desc, et, et)
223 | q = "%s %s %s" % (film, e['seasonNumber'], e['episodeNumber'])
224 | q = q.encode('utf-8')
225 | srt.append((int(e['seasonNumber'])*1000 + int(e['episodeNumber']) , self.GetURL(mode=SEARCH, query=q), listItem))
226 | for el in sorted(srt):
227 | _, q, i = el
228 | xbmcplugin.addDirectoryItem(self.handle, q, i, True)
229 |
230 | def Do_MY_VIDEOS(self):
231 | self.prevPage()
232 | #Albums item
233 | self_vk_id = 0
234 | v = self.api.call("users.get")
235 | if v:
236 | self_vk_id = v[0]["uid"]
237 | listItem = xbmcgui.ListItem(__language__(40002))
238 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode=ALBUM_VIDEO, owner_id=self_vk_id), listItem, True)
239 |
240 | v = self.api.call("video.get", count=self.per_page, offset=self.offset)
241 | if v:
242 | for a in v[1:]:
243 | self.ProcessFoundEntry(a)
244 | self.nextPage(v)
245 |
246 | def Do_ALBUM_VIDEO(self):
247 | self.prevPage()
248 | owner_id = self.params.get("owner_id") or ""
249 | v = self.api.call("video.getAlbums", owner_id=owner_id)
250 | if v:
251 | for a in v[1:]:
252 | title = PrepareString(a["title"])
253 | listItem = xbmcgui.ListItem(title, "")
254 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode="VIDEO_ALBUM_LIST", album_id=a["album_id"], owner_id=owner_id), listItem, True)
255 | self.nextPage(v)
256 |
257 | def Do_VIDEO_ALBUM_LIST(self):
258 | self.prevPage()
259 | owner_id = self.params.get("owner_id") or ""
260 | v = self.api.call("video.get", count=self.per_page, offset=self.offset, album_id=self.params["album_id"], owner_id=owner_id)
261 | if v:
262 | for a in v[1:]:
263 | self.ProcessFoundEntry(a)
264 | self.nextPage(v)
265 |
266 | def Do_TOP_DOWNLOADS(self):
267 | html = urllib.urlopen("http://kinobaza.tv/ratings/top-downloadable").read()
268 | regex = re.compile(r'
.*?(.*?)',re.UNICODE|re.DOTALL)
269 | r = regex.findall(html)
270 | for thumb, ru, en in r:
271 | thumb = thumb.replace('60.jpg','207.jpg')
272 | title = ru.decode("utf-8") + " / " + en.decode('utf-8')
273 | listItem = xbmcgui.ListItem(PrepareString(title) , en, thumb, thumb)
274 | q= ru + " " + en.replace("(","").replace(")","")
275 | xbmcplugin.addDirectoryItem(self.handle, self.GetURL(mode=SEARCH,query=q), listItem, True)
276 |
277 | def Do_MY_SHOWS_LIST(self):
278 | pass
279 |
--------------------------------------------------------------------------------