├── .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 | --------------------------------------------------------------------------------