From 6225ee8b9bd07e99cd41c36c4c6994fbaeaab0db Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Sun, 10 Feb 2013 17:23:01 +0100 Subject: [PATCH 01/76] Add KQOauth lib in thirdparty. --- src/libtomahawk/CMakeLists.txt | 8 + .../thirdparty/kqoauth/LGPL_EXCEPTION.txt | 22 + .../thirdparty/kqoauth/LICENSE.LGPL | 505 ++++++++++++ .../thirdparty/kqoauth/kqoauth2request.cpp | 61 ++ .../thirdparty/kqoauth/kqoauth2request.h | 50 ++ .../thirdparty/kqoauth/kqoauth2request_p.h | 14 + .../kqoauth/kqoauthauthreplyserver.cpp | 140 ++++ .../kqoauth/kqoauthauthreplyserver.h | 52 ++ .../kqoauth/kqoauthauthreplyserver_p.h | 53 ++ .../thirdparty/kqoauth/kqoauthglobals.h | 52 ++ .../thirdparty/kqoauth/kqoauthmanager.cpp | 727 ++++++++++++++++++ .../thirdparty/kqoauth/kqoauthmanager.h | 205 +++++ .../thirdparty/kqoauth/kqoauthmanager_p.h | 78 ++ .../thirdparty/kqoauth/kqoauthrequest.cpp | 625 +++++++++++++++ .../thirdparty/kqoauth/kqoauthrequest.h | 157 ++++ .../thirdparty/kqoauth/kqoauthrequest_1.cpp | 5 + .../thirdparty/kqoauth/kqoauthrequest_1.h | 12 + .../thirdparty/kqoauth/kqoauthrequest_p.h | 98 +++ .../kqoauth/kqoauthrequest_xauth.cpp | 95 +++ .../thirdparty/kqoauth/kqoauthrequest_xauth.h | 53 ++ .../kqoauth/kqoauthrequest_xauth_p.h | 14 + .../thirdparty/kqoauth/kqoauthutils.cpp | 83 ++ .../thirdparty/kqoauth/kqoauthutils.h | 37 + 23 files changed, 3146 insertions(+) create mode 100644 src/libtomahawk/thirdparty/kqoauth/LGPL_EXCEPTION.txt create mode 100644 src/libtomahawk/thirdparty/kqoauth/LICENSE.LGPL create mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauth2request.cpp create mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauth2request.h create mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauth2request_p.h create mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver.cpp create mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver.h create mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver_p.h create mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthglobals.h create mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.cpp create mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.h create mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthmanager_p.h create mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthrequest.cpp create mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthrequest.h create mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_1.cpp create mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_1.h create mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_p.h create mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth.cpp create mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth.h create mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth_p.h create mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthutils.cpp create mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthutils.h diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index cc8d666ee5..1732d3c8a9 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -317,6 +317,14 @@ list(APPEND libSources thirdparty/kdsingleapplicationguard/kdsharedmemorylocker.cpp thirdparty/kdsingleapplicationguard/kdtoolsglobal.cpp thirdparty/kdsingleapplicationguard/kdlockedsharedmemorypointer.cpp + + thirdparty/kqoauth/kqoauth2request.cpp + thirdparty/kqoauth/kqoauthauthreplyserver.cpp + thirdparty/kqoauth/kqoauthmanager.cpp + thirdparty/kqoauth/kqoauthrequest.cpp + thirdparty/kqoauth/kqoauthrequest_1.cpp + thirdparty/kqoauth/kqoauthrequest_xauth.cpp + thirdparty/kqoauth/kqoauthutils.cpp ) IF(LIBLASTFM_FOUND) diff --git a/src/libtomahawk/thirdparty/kqoauth/LGPL_EXCEPTION.txt b/src/libtomahawk/thirdparty/kqoauth/LGPL_EXCEPTION.txt new file mode 100644 index 0000000000..8f73eca773 --- /dev/null +++ b/src/libtomahawk/thirdparty/kqoauth/LGPL_EXCEPTION.txt @@ -0,0 +1,22 @@ +Nokia Qt LGPL Exception version 1.1 + +As an additional permission to the GNU Lesser General Public License version +2.1, the object code form of a "work that uses the Library" may incorporate +material from a header file that is part of the Library. You may distribute +such object code under terms of your choice, provided that: + (i) the header files of the Library have not been modified; and + (ii) the incorporated material is limited to numerical parameters, data + structure layouts, accessors, macros, inline functions and + templates; and + (iii) you comply with the terms of Section 6 of the GNU Lesser General + Public License version 2.1. + +Moreover, you may apply this exception to a modified version of the Library, +provided that such modification does not involve copying material from the +Library into the modified Library's header files unless such material is +limited to (i) numerical parameters; (ii) data structure layouts; +(iii) accessors; and (iv) small macros, templates and inline functions of +five lines or less in length. + +Furthermore, you are not required to apply this additional permission to a +modified version of the Library. diff --git a/src/libtomahawk/thirdparty/kqoauth/LICENSE.LGPL b/src/libtomahawk/thirdparty/kqoauth/LICENSE.LGPL new file mode 100644 index 0000000000..184ea478b2 --- /dev/null +++ b/src/libtomahawk/thirdparty/kqoauth/LICENSE.LGPL @@ -0,0 +1,505 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauth2request.cpp b/src/libtomahawk/thirdparty/kqoauth/kqoauth2request.cpp new file mode 100644 index 0000000000..28ece6973c --- /dev/null +++ b/src/libtomahawk/thirdparty/kqoauth/kqoauth2request.cpp @@ -0,0 +1,61 @@ +/** + * KQOAuth - An OAuth authentication library for Qt. + * + * Author: Johan Paul (johan.paul@d-pointer.com) + * http://www.d-pointer.com + * This file: Kyle Fowler + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * KQOAuth is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * In addition, as a special exception, KQOauth provides you certain additional + * rights. These rights are described in the Nokia Qt LGPL Exception + * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + * + * You should have received a copy of the GNU Lesser General Public License + * along with KQOAuth. If not, see + */ +#include + +#include "kqoauth2request_p.h" +#include "kqoauth2request.h" + +/** + * Private d_ptr implementations. + */ +KQOAuth2Request_Private::KQOAuth2Request_Private() +{ + +} + +KQOAuth2Request_Private::~KQOAuth2Request_Private() +{ +} + +/** + * Public implementations. + */ +KQOAuth2Request::KQOAuth2Request(QObject *parent) : + KQOAuthRequest(parent), + d_ptr(new KQOAuth2Request_Private) +{ +} + +bool KQOAuth2Request::isValid() const { + // Access token must always be retrieved using the POST HTTP method. + // And then check the validity of the XAuth request. + // Provided by the base class as a protected method for us. + return validateOauth2Request(); +} + +void KQOAuth2Request::initRequest(KQOAuthRequest::RequestType type, const QUrl &requestEndpoint) { + KQOAuthRequest::initRequest(type,requestEndpoint); + setRequestOAuthMethod(KQOAuthRequest::OAUTH2); +} diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauth2request.h b/src/libtomahawk/thirdparty/kqoauth/kqoauth2request.h new file mode 100644 index 0000000000..021d159199 --- /dev/null +++ b/src/libtomahawk/thirdparty/kqoauth/kqoauth2request.h @@ -0,0 +1,50 @@ +/** + * KQOAuth - An OAuth authentication library for Qt. + * + * Author: Johan Paul (johan.paul@d-pointer.com) + * http://www.d-pointer.com + * This file: Kyle Fowler + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * KQOAuth is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * In addition, as a special exception, KQOauth provides you certain additional + * rights. These rights are described in the Nokia Qt LGPL Exception + * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + * + * You should have received a copy of the GNU Lesser General Public License + * along with KQOAuth. If not, see . + */ +#ifndef KQOAUTH2REQUEST_H +#define KQOAUTH2REQUEST_H + +#include "kqoauthrequest.h" +#include "kqoauthrequest_1.h" + +class KQOAuth2Request_Private; +class KQOAUTH_EXPORT KQOAuth2Request : public KQOAuthRequest +{ + Q_OBJECT +public: + KQOAuth2Request(QObject *parent = 0); + + /** + * These methods can be overridden in child classes which are different types of + * OAuth requests. + */ + // Validate the request of this type. + bool isValid() const; + void initRequest(KQOAuthRequest::RequestType type, const QUrl &requestEndpoint); + +private: + KQOAuth2Request_Private * const d_ptr; +}; + +#endif // KQOAUTHREQUEST_XAUTH_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauth2request_p.h b/src/libtomahawk/thirdparty/kqoauth/kqoauth2request_p.h new file mode 100644 index 0000000000..2a0dcd3571 --- /dev/null +++ b/src/libtomahawk/thirdparty/kqoauth/kqoauth2request_p.h @@ -0,0 +1,14 @@ +#ifndef KQOAUTH2REQUEST_P_H +#define KQOAUTH2REQUEST_P_H + +#include "kqoauthglobals.h" + +class KQOAuthRequest; +class KQOAUTH_EXPORT KQOAuth2Request_Private +{ +public: + KQOAuth2Request_Private(); + ~KQOAuth2Request_Private(); +}; + +#endif // KQOAUTHREQUEST_XAUTH_P_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver.cpp b/src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver.cpp new file mode 100644 index 0000000000..30f25de61d --- /dev/null +++ b/src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver.cpp @@ -0,0 +1,140 @@ +/** + * KQOAuth - An OAuth authentication library for Qt. + * + * Author: Johan Paul (johan.paul@d-pointer.com) + * http://www.d-pointer.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * KQOAuth is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * In addition, as a special exception, KQOauth provides you certain additional + * rights. These rights are described in the Nokia Qt LGPL Exception + * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + * + * You should have received a copy of the GNU Lesser General Public License + * along with KQOAuth. If not, see + */ +#include +#include +#include +#include +#include +#include + +#include "kqoauthauthreplyserver.h" +#include "kqoauthauthreplyserver_p.h" + +KQOAuthAuthReplyServerPrivate::KQOAuthAuthReplyServerPrivate(KQOAuthAuthReplyServer *parent): + q_ptr(parent) +{ + +} + +KQOAuthAuthReplyServerPrivate::~KQOAuthAuthReplyServerPrivate() +{ + +} + +void KQOAuthAuthReplyServerPrivate::onIncomingConnection() { + Q_Q(KQOAuthAuthReplyServer); + qDebug() << "Incoming Connection"; + socket = q->nextPendingConnection(); + connect(socket, SIGNAL(readyRead()), + this, SLOT(onBytesReady()), Qt::UniqueConnection); +} + +void KQOAuthAuthReplyServerPrivate::onBytesReady() { + Q_Q(KQOAuthAuthReplyServer); + qDebug() << "Socket peer host address: " << socket->peerAddress(); + QByteArray reply; + QByteArray content; + + QByteArray data = socket->readAll(); + qDebug()<< "Query Data: " << data; + QMultiMap queryParams = parseQueryParams(&data); + if(queryParams.size() == 0 && !handlingRedirect) { //assume theres a hash and do the redirect hack + handlingRedirect = true; + content.append("

Account authorized, go ahead back to the tumblr app and start your experience!

"); + } else { + handlingRedirect = false; + QFile file("app/native/assets/" + localFile); + QString fileData; + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { + qDebug() << "file worked"; + QTextStream in(&file); + while (!in.atEnd()) { + fileData += in.readLine(); + } + file.close(); + } + if(fileData.isEmpty()) { + content.append("

Account linked, go ahead back to the app and check the status!

"); + } else { + content.append(fileData); + } + } + + reply.append("HTTP/1.0 200 OK \r\n"); + reply.append("Content-Type: text/html; charset=\"utf-8\"\r\n"); + reply.append(QString("Content-Length: %1\r\n").arg(content.size())); + reply.append("\r\n"); + reply.append(content); + socket->write(reply); + + if(!handlingRedirect) { + socket->disconnectFromHost(); + q->close(); + emit q->verificationReceived(queryParams); + } +} + +QMultiMap KQOAuthAuthReplyServerPrivate::parseQueryParams(QByteArray *data) { + QString splitGetLine = QString(*data).split("\r\n").first(); // Retrieve the first line with query params. + splitGetLine.remove("GET "); // Clean the line from GET + splitGetLine.remove("HTTP/1.1"); // From HTTP + splitGetLine.remove("\r\n"); // And from rest. + splitGetLine.prepend("http://localhost"); // Now, make it a URL + + QUrl getTokenUrl(splitGetLine); + QList< QPair > tokens = getTokenUrl.queryItems(); // Ask QUrl to do our work. + + QMultiMap queryParams; + QPair tokenPair; + foreach (tokenPair, tokens) { + queryParams.insert(tokenPair.first.trimmed(), tokenPair.second.trimmed()); + } + + return queryParams; +} + + + +KQOAuthAuthReplyServer::KQOAuthAuthReplyServer(QObject *parent) : + QTcpServer(parent), + d_ptr( new KQOAuthAuthReplyServerPrivate(this) ) +{ + Q_D(KQOAuthAuthReplyServer); + + connect(this, SIGNAL(newConnection()), + d, SLOT(onIncomingConnection())); +} + +KQOAuthAuthReplyServer::~KQOAuthAuthReplyServer() +{ + delete d_ptr; +} + + +void KQOAuthAuthReplyServer::setSuccessHtmlFile(QString filePath) { + Q_D(KQOAuthAuthReplyServer); + d->localFile = filePath; +} + + diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver.h new file mode 100644 index 0000000000..82f6d99d24 --- /dev/null +++ b/src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver.h @@ -0,0 +1,52 @@ +/** + * KQOAuth - An OAuth authentication library for Qt. + * + * Author: Johan Paul (johan.paul@d-pointer.com) + * http://www.d-pointer.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * KQOAuth is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * In addition, as a special exception, KQOauth provides you certain additional + * rights. These rights are described in the Nokia Qt LGPL Exception + * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + * + * You should have received a copy of the GNU Lesser General Public License + * along with KQOAuth. If not, see + */ +#ifndef KQOAUTHAUTHREPLYSERVER_H +#define KQOAUTHAUTHREPLYSERVER_H + +#include + +#include "kqoauthglobals.h" + +class KQOAuthAuthReplyServerPrivate; +class KQOAUTH_EXPORT KQOAuthAuthReplyServer : public QTcpServer +{ + Q_OBJECT +public: + explicit KQOAuthAuthReplyServer(QObject *parent); + ~KQOAuthAuthReplyServer(); + void setSuccessHtmlFile(QString filePath); + +Q_SIGNALS: + void verificationReceived(QMultiMap); + + +private: + KQOAuthAuthReplyServerPrivate * const d_ptr; + Q_DECLARE_PRIVATE(KQOAuthAuthReplyServer); + Q_DISABLE_COPY(KQOAuthAuthReplyServer); + + +}; + +#endif // KQOAUTHAUTHREPLYSERVER_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver_p.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver_p.h new file mode 100644 index 0000000000..8da4d582e3 --- /dev/null +++ b/src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver_p.h @@ -0,0 +1,53 @@ +/** + * KQOAuth - An OAuth authentication library for Qt. + * + * Author: Johan Paul (johan.paul@d-pointer.com) + * http://www.d-pointer.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * KQOAuth is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * In addition, as a special exception, KQOauth provides you certain additional + * rights. These rights are described in the Nokia Qt LGPL Exception + * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + * + * You should have received a copy of the GNU Lesser General Public License + * along with KQOAuth. If not, see + */ +// Note this class shouldn't be copied or used and the implementation might change later. +#ifndef KQOAUTHAUTHREPLYSERVER_P_H +#define KQOAUTHAUTHREPLYSERVER_P_H + +#include "kqoauthauthreplyserver.h" +#include +#include + +class KQOAUTH_EXPORT KQOAuthAuthReplyServerPrivate: public QObject +{ + Q_OBJECT +public: + KQOAuthAuthReplyServerPrivate( KQOAuthAuthReplyServer * parent ); + ~KQOAuthAuthReplyServerPrivate(); + QMultiMap parseQueryParams(QByteArray *sdata); + +public Q_SLOTS: + void onIncomingConnection(); + void onBytesReady(); + +public: + KQOAuthAuthReplyServer * q_ptr; + Q_DECLARE_PUBLIC(KQOAuthAuthReplyServer); + QTcpSocket *socket; + QString localFile; +private: + bool handlingRedirect; +}; + +#endif // KQOAUTHAUTHREPLYSERVER_P_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthglobals.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthglobals.h new file mode 100644 index 0000000000..203716f764 --- /dev/null +++ b/src/libtomahawk/thirdparty/kqoauth/kqoauthglobals.h @@ -0,0 +1,52 @@ +/** + * KQOAuth - An OAuth authentication library for Qt. + * + * Author: Johan Paul (johan.paul@d-pointer.com) + * http://www.d-pointer.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * KQOAuth is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * In addition, as a special exception, KQOauth provides you certain additional + * rights. These rights are described in the Nokia Qt LGPL Exception + * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + * + * You should have received a copy of the GNU Lesser General Public License + * along with KQOAuth. If not, see + */ +#ifndef KQOAUTHGLOBALS_H +#define KQOAUTHGLOBALS_H + +#include + +#if defined(KQOAUTH) +# define KQOAUTH_EXPORT Q_DECL_EXPORT +#else +# define KQOAUTH_EXPORT Q_DECL_IMPORT +#endif + +//////////// Static constant definitions /////////// +const QString OAUTH_KEY_CONSUMER("oauth_consumer"); +const QString OAUTH_KEY_CONSUMER_KEY("oauth_consumer_key"); +const QString OAUTH_KEY_TOKEN("oauth_token"); +const QString OAUTH_KEY_TOKEN_SECRET("oauth_token_secret"); +const QString OAUTH_KEY_SIGNATURE_METHOD("oauth_signature_method"); +const QString OAUTH_KEY_TIMESTAMP("oauth_timestamp"); +const QString OAUTH_KEY_NONCE("oauth_nonce"); +const QString OAUTH_KEY_SIGNATURE("oauth_signature"); +const QString OAUTH_KEY_CALLBACK("oauth_callback"); +const QString OAUTH_KEY_VERIFIER("oauth_verifier"); +const QString OAUTH_KEY_VERSION("oauth_version"); +const QString OAUTH2_KEY_CLIENT_ID("client_id"); +const QString OAUTH2_KEY_CLIENT_SECRET("client_secret"); +const QString OAUTH2_KEY_REDIRECT_URI("redirect_uri"); +const QString OAUTH2_KEY_RESPONSE_TYPE("response_type"); + +#endif // KQOAUTHGLOBALS_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.cpp b/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.cpp new file mode 100644 index 0000000000..0e24b43f92 --- /dev/null +++ b/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.cpp @@ -0,0 +1,727 @@ +/** + * KQOAuth - An OAuth authentication library for Qt. + * + * Author: Johan Paul (johan.paul@d-pointer.com) + * http://www.d-pointer.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * KQOAuth is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * In addition, as a special exception, KQOauth provides you certain additional + * rights. These rights are described in the Nokia Qt LGPL Exception + * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + * + * You should have received a copy of the GNU Lesser General Public License + * along with KQOAuth. If not, see + */ +#include +#include + +#include "kqoauthmanager.h" +#include "kqoauthmanager_p.h" + + +////////////// Private d_ptr implementation //////////////// + +KQOAuthManagerPrivate::KQOAuthManagerPrivate(KQOAuthManager *parent) : + error(KQOAuthManager::NoError) , + r(0) , + opaqueRequest(new KQOAuthRequest) , + q_ptr(parent) , + callbackServer(new KQOAuthAuthReplyServer(parent)) , + isVerified(false) , + isAuthorized(false) , + autoAuth(false), + networkManager(new QNetworkAccessManager), + managerUserSet(false) +{ + +} + +KQOAuthManagerPrivate::~KQOAuthManagerPrivate() { + delete opaqueRequest; + opaqueRequest = 0; + + if (!managerUserSet) { + delete networkManager; + networkManager = 0; + } +} + +QList< QPair > KQOAuthManagerPrivate::createQueryParams(const KQOAuthParameters &requestParams) { + QList requestKeys = requestParams.keys(); + QList requestValues = requestParams.values(); + + QList< QPair > result; + for(int i=0; i KQOAuthManagerPrivate::createTokensFromResponse(QByteArray reply) { + QMultiMap result; + QString replyString(reply); + + QStringList parameterPairs = replyString.split('&', QString::SkipEmptyParts); + foreach (const QString ¶meterPair, parameterPairs) { + QStringList parameter = parameterPair.split('='); + result.insert(parameter.value(0), parameter.value(1)); + } + + return result; +} + +bool KQOAuthManagerPrivate::setSuccessfulRequestToken(const QMultiMap &request) { + if (currentRequestType == KQOAuthRequest::TemporaryCredentials) { + hasTemporaryToken = (!QString(request.value("oauth_token")).isEmpty() && !QString(request.value("oauth_token_secret")).isEmpty()); + } else { + return false; + } + + if (hasTemporaryToken) { + requestToken = QUrl::fromPercentEncoding( QString(request.value("oauth_token")).toLocal8Bit() ); + requestTokenSecret = QUrl::fromPercentEncoding( QString(request.value("oauth_token_secret")).toLocal8Bit() ); + } + + return hasTemporaryToken; +} + +bool KQOAuthManagerPrivate::setSuccessfulAuthorized(const QMultiMap &request ) { + if (currentRequestType == KQOAuthRequest::AccessToken) { + isAuthorized = (!QString(request.value("oauth_token")).isEmpty() && !QString(request.value("oauth_token_secret")).isEmpty()); + } else { + return false; + } + + if (isAuthorized) { + requestToken = QUrl::fromPercentEncoding( QString(request.value("oauth_token")).toLocal8Bit() ); + requestTokenSecret = QUrl::fromPercentEncoding( QString(request.value("oauth_token_secret")).toLocal8Bit() ); + } + + return isAuthorized; +} + +void KQOAuthManagerPrivate::emitTokens() { + Q_Q(KQOAuthManager); + + if (this->requestToken.isEmpty() || this->requestTokenSecret.isEmpty()) { + error = KQOAuthManager::RequestUnauthorized; + } + + if (currentRequestType == KQOAuthRequest::TemporaryCredentials) { + // Signal that we are ready to use the protected resources. + emit q->temporaryTokenReceived(this->requestToken, this->requestTokenSecret); + } + + if (currentRequestType == KQOAuthRequest::AccessToken) { + // Signal that we are ready to use the protected resources. + emit q->accessTokenReceived(this->requestToken, this->requestTokenSecret); + } + + emit q->receivedToken(this->requestToken, this->requestTokenSecret); +} + +bool KQOAuthManagerPrivate::setupCallbackServer() { + return callbackServer->listen(); +} + + +/////////////// Public implementation //////////////// + +KQOAuthManager::KQOAuthManager(QObject *parent) : + QObject(parent) , + d_ptr(new KQOAuthManagerPrivate(this)) +{ + +} + +KQOAuthManager::~KQOAuthManager() +{ + delete d_ptr; +} + +void KQOAuthManager::executeRequest(KQOAuthRequest *request) { + Q_D(KQOAuthManager); + + d->r = request; + + if (request == 0) { + qWarning() << "Request is NULL. Cannot proceed."; + d->error = KQOAuthManager::RequestError; + return; + } + + if (!request->requestEndpoint().isValid()) { + qDebug() << request->requestEndpoint(); + qWarning() << "Request endpoint URL is not valid. Cannot proceed."; + d->error = KQOAuthManager::RequestEndpointError; + return; + } + + if (!request->isValid()) { + qWarning() << "Request is not valid. Cannot proceed."; + d->error = KQOAuthManager::RequestValidationError; + return; + } + + d->currentRequestType = request->requestType(); + + QNetworkRequest networkRequest; + networkRequest.setUrl( request->requestEndpoint() ); + + if (d->autoAuth && d->currentRequestType == KQOAuthRequest::TemporaryCredentials) { + d->setupCallbackServer(); + connect(d->callbackServer, SIGNAL(verificationReceived(QMultiMap)), + this, SLOT( onVerificationReceived(QMultiMap))); + + QString serverString = "http://localhost:"; + serverString.append(QString::number(d->callbackServer->serverPort())); + request->setCallbackUrl(QUrl(serverString)); + qDebug() << serverString; + } + + // And now fill the request with "Authorization" header data. + QList requestHeaders = request->requestParameters(); + QByteArray authHeader; + + bool first = true; + foreach (const QByteArray header, requestHeaders) { + if (!first) { + authHeader.append(", "); + } else { + authHeader.append("OAuth "); + first = false; + } + + authHeader.append(header); + } + networkRequest.setRawHeader("Authorization", authHeader); + + connect(d->networkManager, SIGNAL(finished(QNetworkReply *)), + this, SLOT(onRequestReplyReceived(QNetworkReply *)), Qt::UniqueConnection); + disconnect(d->networkManager, SIGNAL(finished(QNetworkReply *)), + this, SLOT(onAuthorizedRequestReplyReceived(QNetworkReply *))); + + if (request->httpMethod() == KQOAuthRequest::GET) { + // Get the requested additional params as a list of pairs we can give QUrl + QList< QPair > urlParams = d->createQueryParams(request->additionalParameters()); + + // Take the original URL and append the query params to it. + QUrl urlWithParams = networkRequest.url(); + urlWithParams.setQueryItems(urlParams); + networkRequest.setUrl(urlWithParams); + + // Submit the request including the params. + QNetworkReply *reply = d->networkManager->get(networkRequest); + reply->ignoreSslErrors(); + connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), + this, SLOT(slotError(QNetworkReply::NetworkError))); + + } else if (request->httpMethod() == KQOAuthRequest::POST) { + + networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, request->contentType()); + + qDebug() << networkRequest.rawHeaderList(); + qDebug() << networkRequest.rawHeader("Authorization"); + qDebug() << networkRequest.rawHeader("Content-Type"); + + QNetworkReply *reply; + if (request->contentType() == "application/x-www-form-urlencoded") { + reply = d->networkManager->post(networkRequest, request->requestBody()); + } else { + reply = d->networkManager->post(networkRequest, request->rawData()); + } + reply->ignoreSslErrors(); + + connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), + this, SLOT(slotError(QNetworkReply::NetworkError))); + } + + d->r->requestTimerStart(); +} + +void KQOAuthManager::executeAuthorizedRequest(KQOAuthRequest *request, int id) { + Q_D(KQOAuthManager); + + d->r = request; + + if (request == 0) { + qWarning() << "Request is NULL. Cannot proceed."; + d->error = KQOAuthManager::RequestError; + return; + } + + if (!request->requestEndpoint().isValid()) { + qDebug() << request->requestEndpoint(); + qWarning() << "Request endpoint URL is not valid. Cannot proceed."; + d->error = KQOAuthManager::RequestEndpointError; + return; + } + + if (!request->isValid()) { + qWarning() << "Request is not valid. Cannot proceed."; + d->error = KQOAuthManager::RequestValidationError; + return; + } + + d->currentRequestType = request->requestType(); + + QNetworkRequest networkRequest; + networkRequest.setUrl( request->requestEndpoint() ); + + if ( d->currentRequestType != KQOAuthRequest::AuthorizedRequest){ + qWarning() << "Not Authorized Request. Cannot proceed"; + d->error = KQOAuthManager::RequestError; + return; + } + + if(request->oauthMethod() != KQOAuthRequest::OAUTH2) { + // And now fill the request with "Authorization" header data. + QList requestHeaders = request->requestParameters(); + QByteArray authHeader; + + bool first = true; + foreach (const QByteArray header, requestHeaders) { + if (!first) { + authHeader.append(", "); + } else { + authHeader.append("OAuth "); + first = false; + } + + authHeader.append(header); + } + networkRequest.setRawHeader("Authorization", authHeader); + } + + + disconnect(d->networkManager, SIGNAL(finished(QNetworkReply *)), + this, SLOT(onRequestReplyReceived(QNetworkReply *))); + connect(d->networkManager, SIGNAL(finished(QNetworkReply *)), + this, SLOT(onAuthorizedRequestReplyReceived(QNetworkReply*)), Qt::UniqueConnection); + + if (request->httpMethod() == KQOAuthRequest::GET) { + // Get the requested additional params as a list of pairs we can give QUrl + QList< QPair > urlParams = d->createQueryParams(request->additionalParameters()); + + // Take the original URL and append the query params to it. + QUrl urlWithParams = networkRequest.url(); + urlWithParams.setQueryItems(urlParams); + networkRequest.setUrl(urlWithParams); + qDebug() << networkRequest.url(); + + // Submit the request including the params. + QNetworkReply *reply = d->networkManager->get(networkRequest); + reply->ignoreSslErrors(); + connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), + this, SLOT(slotError(QNetworkReply::NetworkError))); + + } else if (request->httpMethod() == KQOAuthRequest::POST) { + + networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, request->contentType()); + + qDebug() << networkRequest.rawHeaderList(); + qDebug() << networkRequest.rawHeader("Authorization"); + qDebug() << networkRequest.rawHeader("Content-Type"); + + QNetworkReply *reply; + if (request->contentType() == "application/x-www-form-urlencoded") { + reply = d->networkManager->post(networkRequest, request->requestBody()); + } else { + reply = d->networkManager->post(networkRequest, request->rawData()); + } + reply->ignoreSslErrors(); + + d->requestIds.insert(reply, id); + + connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), + this, SLOT(slotError(QNetworkReply::NetworkError))); + } + + d->r->requestTimerStart(); +} + + +void KQOAuthManager::setHandleUserAuthorization(bool set) { + Q_D(KQOAuthManager); + + d->autoAuth = set; +} + +bool KQOAuthManager::hasTemporaryToken() { + Q_D(KQOAuthManager); + + return d->hasTemporaryToken; +} + +bool KQOAuthManager::isVerified() { + Q_D(KQOAuthManager); + + return d->isVerified; +} + +bool KQOAuthManager::isAuthorized() { + Q_D(KQOAuthManager); + + return d->isAuthorized; +} + +KQOAuthManager::KQOAuthError KQOAuthManager::lastError() { + Q_D(KQOAuthManager); + + return d->error; +} + +void KQOAuthManager::setNetworkManager(QNetworkAccessManager *manager) { + Q_D(KQOAuthManager); + + if (manager == 0) { + d->error = KQOAuthManager::ManagerError; + return; + } + + if (!d->managerUserSet) { + delete d->networkManager; + } + + d->managerUserSet = true; + d->networkManager = manager; +} + +QNetworkAccessManager * KQOAuthManager::networkManager() const { + Q_D(const KQOAuthManager); + + if (d->managerUserSet) { + return d->networkManager; + } else { + return NULL; + } + +} + +void KQOAuthManager::setSuccessHtmlFile(QString file) { + Q_D(KQOAuthManager); + d->successHtmlFile = file; + d->callbackServer->setSuccessHtmlFile(file); +} + + +//////////// Public convenience API ///////////// +void KQOAuthManager::getOauth2UserAuthorization(QUrl authorizationEndpoint, QString consumerKey, const KQOAuthParameters &additionalParams) { + Q_D(KQOAuthManager); + + d->setupCallbackServer(); + connect(d->callbackServer, SIGNAL(verificationReceived(QMultiMap)), + this, SLOT( onOauth2VerificationReceived(QMultiMap))); + + QString serverString = "http://localhost:"; + serverString.append(QString::number(d->callbackServer->serverPort())); + QUrl openWebPageUrl(authorizationEndpoint.toString(), QUrl::StrictMode); + openWebPageUrl.addQueryItem(OAUTH2_KEY_CLIENT_ID, consumerKey); + openWebPageUrl.addQueryItem(OAUTH2_KEY_RESPONSE_TYPE, "token"); + openWebPageUrl.addQueryItem(OAUTH2_KEY_REDIRECT_URI, serverString); + if(additionalParams.size() > 0) { + QList< QPair > urlParams = d->createQueryParams(additionalParams); + for(int i=0; i < urlParams.length(); i++){ + openWebPageUrl.addQueryItem(urlParams[i].first, urlParams[i].second); + } + } + qDebug() << openWebPageUrl.toString(); + QDesktopServices::openUrl(openWebPageUrl); + //navigator_invoke(openWebPageUrl.toString().toStdString().c_str(),0); +} + +QUrl KQOAuthManager::getUserAuthorizationUrl(QUrl authorizationEndpoint) { + Q_D(KQOAuthManager); + + if (!d->hasTemporaryToken) { + qWarning() << "No temporary tokens retreieved. Cannot get user authorization."; + d->error = KQOAuthManager::RequestUnauthorized; + return QUrl(); + } + + if (!authorizationEndpoint.isValid()) { + qWarning() << "Authorization endpoint not valid. Cannot proceed."; + d->error = KQOAuthManager::RequestEndpointError; + return QUrl(); + } + + d->error = KQOAuthManager::NoError; + + QPair tokenParam = qMakePair(QString("oauth_token"), QString(d->requestToken)); + QUrl openWebPageUrl(authorizationEndpoint.toString(), QUrl::StrictMode); + openWebPageUrl.addQueryItem(tokenParam.first, tokenParam.second); + + qDebug() << openWebPageUrl.toString(); + return openWebPageUrl; +} + +void KQOAuthManager::getUserAuthorization(QUrl authorizationEndpoint) { + QUrl openWebPageUrl = getUserAuthorizationUrl(authorizationEndpoint); + + if(!openWebPageUrl.isEmpty()) { + // Open the user's default browser to the resource authorization page provided + // by the service. + + QDesktopServices::openUrl(openWebPageUrl); + //navigator_invoke(openWebPageUrl.toString().toStdString().c_str(),0); + } +} + +void KQOAuthManager::getUserAccessTokens(QUrl accessTokenEndpoint) { + Q_D(KQOAuthManager); + + if (!d->isVerified) { + qWarning() << "Not verified. Cannot get access tokens."; + d->error = KQOAuthManager::RequestUnauthorized; + return; + } + + if (!accessTokenEndpoint.isValid()) { + qWarning() << "Endpoint for access token exchange is not valid. Cannot proceed."; + d->error = KQOAuthManager::RequestEndpointError; + return; + } + + d->error = KQOAuthManager::NoError; + + d->opaqueRequest->clearRequest(); + d->opaqueRequest->initRequest(KQOAuthRequest::AccessToken, accessTokenEndpoint); + d->opaqueRequest->setToken(d->requestToken); + d->opaqueRequest->setTokenSecret(d->requestTokenSecret); + d->opaqueRequest->setVerifier(d->requestVerifier); + d->opaqueRequest->setConsumerKey(d->consumerKey); + d->opaqueRequest->setConsumerSecretKey(d->consumerKeySecret); + + executeRequest(d->opaqueRequest); +} + +void KQOAuthManager::sendAuthorizedRequest(QUrl requestEndpoint, const KQOAuthParameters &requestParameters) { + Q_D(KQOAuthManager); + + if (!d->isAuthorized) { + qWarning() << "No access tokens retrieved. Cannot send authorized requests."; + d->error = KQOAuthManager::RequestUnauthorized; + return; + } + + if (!requestEndpoint.isValid()) { + qWarning() << "Endpoint for authorized request is not valid. Cannot proceed."; + d->error = KQOAuthManager::RequestEndpointError; + return; + } + + d->error = KQOAuthManager::NoError; + + d->opaqueRequest->clearRequest(); + d->opaqueRequest->initRequest(KQOAuthRequest::AuthorizedRequest, requestEndpoint); + d->opaqueRequest->setAdditionalParameters(requestParameters); + d->opaqueRequest->setToken(d->requestToken); + d->opaqueRequest->setTokenSecret(d->requestTokenSecret); + d->opaqueRequest->setConsumerKey(d->consumerKey); + d->opaqueRequest->setConsumerSecretKey(d->consumerKeySecret); + + executeRequest(d->opaqueRequest); +} + + +/////////////// Private slots ////////////////// + +void KQOAuthManager::onRequestReplyReceived( QNetworkReply *reply ) { + Q_D(KQOAuthManager); + + QNetworkReply::NetworkError networkError = reply->error(); + switch (networkError) { + case QNetworkReply::NoError: + d->error = KQOAuthManager::NoError; + break; + + case QNetworkReply::ContentAccessDenied: + case QNetworkReply::AuthenticationRequiredError: + d->error = KQOAuthManager::RequestUnauthorized; + break; + + default: + d->error = KQOAuthManager::NetworkError; + break; + } + + // Let's disconnect this slot first + /* + disconnect(d->networkManager, SIGNAL(finished(QNetworkReply *)), + this, SLOT(onRequestReplyReceived(QNetworkReply *))); + */ + + // Read the content of the reply from the network. + QByteArray networkReply = reply->readAll(); + + // Stop any timer we have set on the request. + d->r->requestTimerStop(); + + // Just don't do anything if we didn't get anything useful. + if(networkReply.isEmpty()) { + reply->deleteLater(); + return; + } + QMultiMap responseTokens; + + // We need to emit the signal even if we got an error. + if (d->error != KQOAuthManager::NoError) { + reply->deleteLater(); + emit requestReady(networkReply); + d->emitTokens(); + return; + } + + responseTokens = d->createTokensFromResponse(networkReply); + d->opaqueRequest->clearRequest(); + d->opaqueRequest->setHttpMethod(KQOAuthRequest::POST); // XXX FIXME: Convenient API does not support GET + if (!d->isAuthorized || !d->isVerified) { + if (d->setSuccessfulRequestToken(responseTokens)) { + qDebug() << "Successfully got request tokens."; + d->consumerKey = d->r->consumerKeyForManager(); + d->consumerKeySecret = d->r->consumerKeySecretForManager(); + d->opaqueRequest->setSignatureMethod(KQOAuthRequest::HMAC_SHA1); + d->opaqueRequest->setCallbackUrl(d->r->callbackUrlForManager()); + + d->emitTokens(); + + } else if (d->setSuccessfulAuthorized(responseTokens)) { + qDebug() << "Successfully got access tokens."; + d->opaqueRequest->setSignatureMethod(KQOAuthRequest::HMAC_SHA1); + + d->emitTokens(); + } else if (d->currentRequestType == KQOAuthRequest::AuthorizedRequest) { + emit authorizedRequestDone(); + } + } + + emit requestReady(networkReply); + + reply->deleteLater(); // We need to clean this up, after the event processing is done. +} + +void KQOAuthManager::onAuthorizedRequestReplyReceived( QNetworkReply *reply ) { + Q_D(KQOAuthManager); + + QNetworkReply::NetworkError networkError = reply->error(); + switch (networkError) { + case QNetworkReply::NoError: + d->error = KQOAuthManager::NoError; + break; + + case QNetworkReply::ContentAccessDenied: + case QNetworkReply::AuthenticationRequiredError: + d->error = KQOAuthManager::RequestUnauthorized; + break; + + default: + d->error = KQOAuthManager::NetworkError; + break; + } + + /* + disconnect(d->networkManager, SIGNAL(finished(QNetworkReply *)), + this, SLOT(onAuthorizedRequestReplyReceived(QNetworkReply *))); + */ + + // Read the content of the reply from the network. + QByteArray networkReply = reply->readAll(); + + // Stop any timer we have set on the request. + d->r->requestTimerStop(); + + // Just don't do anything if we didn't get anything useful. + if(networkReply.isEmpty()) { + reply->deleteLater(); + return; + } + + // We need to emit the signal even if we got an error. + if (d->error != KQOAuthManager::NoError) { + qWarning() << "Network reply error"; + return; + } + + + d->opaqueRequest->clearRequest(); + d->opaqueRequest->setHttpMethod(KQOAuthRequest::POST); // XXX FIXME: Convenient API does not support GET + if (d->currentRequestType == KQOAuthRequest::AuthorizedRequest) { + emit authorizedRequestDone(); + } + + int id = d->requestIds.take(reply); + emit authorizedRequestReady(networkReply, id); + reply->deleteLater(); +} + + +void KQOAuthManager::onVerificationReceived(QMultiMap response) { + Q_D(KQOAuthManager); + + QString token = response.value("oauth_token"); + QString verifier = response.value("oauth_verifier"); + if (verifier.isEmpty()) { + d->error = KQOAuthManager::RequestUnauthorized; + } + + verifier = QUrl::fromPercentEncoding(verifier.toUtf8()); // We get the raw URL response here so we need to convert it back + // to plain string so we can percent encode it again later in requests. + + if (d->error == KQOAuthManager::NoError) { + d->requestVerifier = verifier; + d->isVerified = true; + } + + emit authorizationReceived(token, verifier); +} + +void KQOAuthManager::onOauth2VerificationReceived(QMultiMap response) { + Q_D(KQOAuthManager); + + foreach(QString key, response.keys()){ + qDebug() << key; + } + + QString token = response.value("access_token"); + if (token.isEmpty()) { + d->error = KQOAuthManager::RequestUnauthorized; + } + + if (d->error == KQOAuthManager::NoError) { + d->isVerified = true; + } + + emit authorizationReceived(token, NULL); +} + +void KQOAuthManager::slotError(QNetworkReply::NetworkError error) { + Q_UNUSED(error) + Q_D(KQOAuthManager); + + d->error = KQOAuthManager::NetworkError; + QByteArray emptyResponse; + emit requestReady(emptyResponse); + emit authorizedRequestDone(); + + QNetworkReply *reply = qobject_cast(sender()); + d->requestIds.remove(reply); + reply->deleteLater(); +} + +void KQOAuthManager::onSslError(QNetworkReply *reply, const QList &errors) { + Q_UNUSED(errors); + reply->ignoreSslErrors(); +} + diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.h new file mode 100644 index 0000000000..6778626de3 --- /dev/null +++ b/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.h @@ -0,0 +1,205 @@ +/** + * KQOAuth - An OAuth authentication library for Qt. + * + * Author: Johan Paul (johan.paul@d-pointer.com) + * http://www.d-pointer.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * KQOAuth is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * In addition, as a special exception, KQOauth provides you certain additional + * rights. These rights are described in the Nokia Qt LGPL Exception + * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + * + * You should have received a copy of the GNU Lesser General Public License + * along with KQOAuth. If not, see + */ +#ifndef KQOAUTHMANAGER_H +#define KQOAUTHMANAGER_H + +#include +#include +#include + +#include "kqoauthrequest.h" + +class KQOAuthRequest; +class KQOAuthManagerThread; +class KQOAuthManagerPrivate; +class QNetworkAccessManager; +class QUrl; +class QByteArray; +class KQOAUTH_EXPORT KQOAuthManager : public QObject +{ + Q_OBJECT +public: + + enum KQOAuthError { + NoError, // No error + NetworkError, // Network error: timeout, cannot connect. + RequestEndpointError, // Request endpoint is not valid. + RequestValidationError, // Request is not valid: some parameter missing? + RequestUnauthorized, // Authorization error: trying to access a resource without tokens. + RequestError, // The given request to KQOAuthManager is invalid: NULL?, + ManagerError // Manager error, cannot use for sending requests. + }; + + explicit KQOAuthManager(QObject *parent = 0); + ~KQOAuthManager(); + + KQOAuthError lastError(); + + /** + * The manager executes the given request. It takes the HTTP parameters from the + * request and uses QNetworkAccessManager to submit the HTTP request to the net. + * When the request is done it will emit signal requestReady(QByteArray networkReply). + * NOTE: At the moment there is no timeout for the request. + */ + void executeRequest(KQOAuthRequest *request); + void executeAuthorizedRequest(KQOAuthRequest *request, int id); + /** + * Indicates to the user that KQOAuthManager should handle user authorization by + * opening the user's default browser and parsing the reply from the service. + * By setting the parameter to true, KQOAuthManager will store intermediate results + * of the OAuth 1.0 process in its own opaque request. This information is used in + * the user authorization process and also when calling sendAuthorizedRequest(). + * NOTE: You need to set this to true if you want to use getUserAccessTokens() or + * sendAuthorizedRequest(). + */ + void setHandleUserAuthorization(bool set); + + /** + * Returns true if the KQOAuthManager has retrieved the oauth_token value. Otherwise + * return false. + */ + bool hasTemporaryToken(); + /** + * Returns true if the user has authorized us to use the protected resources. Otherwise + * returns false. + * NOTE: In order for KQOAuthManager to know if the user has authorized us to use the + * protected resources, KQOAuthManager must be in control of the user authorization + * process. Hence, this returns true if setHandleUserAuthorization() is set to true + * and the user is authorized with getUserAuthorization(). + */ + bool isVerified(); + /** + * Returns true if KQOAuthManager has the access token and hence can access the protected + * resources. Otherwise returns false. + * NOTE: In order for KQOAuthManager to know if we have access to protected resource + * KQOAuthManager must be in control of the user authorization process and requesting + * the acess token. Hence, this returns true if setHandleUserAuthorization() is set to true + * and the user is authorized with getUserAuthorization() and the access token must be retrieved + * with getUserAccessTokens. + */ + bool isAuthorized(); + + /** + * Sets the file path string that the local server will serve on a successful authentication. This will generally direct + * your user to go back to your application and continue using the app. + */ + void setSuccessHtmlFile(QString filePath); + + /** + * This is a convenience API for authorizing the user. + * The call will verify that a temporary token was received and return the url that the user needs to + * use to authorize the app, it will not open the user's default browser. + */ + QUrl getUserAuthorizationUrl(QUrl authorizationEndpoint); + /** + * This is a convenience API for authorizing the user. + * The call will open the user's default browser, setup a local HTTP server and parse the reply from the + * service after the user has authorized us to access protected resources. If the user authorizes + * us to access protected resources, the verifier token is stored in KQOAuthManager for further use. + * In order to use this method, you must set setHandleUserAuthorization() to true. + */ + void getUserAuthorization(QUrl authorizationEndpoint); + /** + * This is a convenience API for retrieving the access token in exchange for the temporary token and the + * verifier. + * This call will create a KQOAuthRequest and use the previously stored temporary token and verifier to + * exchange for the access token, which will be used to access the protected resources. + * Note that in order to use this method, KQOAuthManager must be in control of the user authorization process. + * Set setHandleUserAuthorization() to true and retrieve user authorization with void getUserAuthorization. + */ + void getUserAccessTokens(QUrl accessTokenEndpoint); + /** + * This is a method for bypassing all the oauth1 auth process and using the browser based oauth2 flow. This will + * launch the browser and set the callback url pointed to a localhost url. Make sure your oauth2 service supports redirect_uri param. + * Add any other params in the additionalParams args like scope or state or any other + */ + void getOauth2UserAuthorization(QUrl authorizationEndpoint, QString consumerKey, const KQOAuthParameters &additionalParams); + /** + * Sends a request to the protected resources. Parameters for the request are service specific and + * are given to the 'requestParameters' as parameters. + * Note that in order to use this method, KQOAuthManager must be in control of the user authorization process. + * Set setHandleUserAuthorization() to true and retrieve user authorization with void getUserAuthorization. + */ + void sendAuthorizedRequest(QUrl requestEndpoint, const KQOAuthParameters &requestParameters); + + /** + * Sets a custom QNetworkAccessManager to handle network requests. This method can be useful if the + * application is using some proxy settings for example. + * The application is responsible for deleting this manager. KQOAuthManager will not delete any + * previously given manager. + * If the manager is NULL, the manager will not be set and the KQOAuthManager::Error. + * If no manager is given, KQOAuthManager will use the default one it will create by itself. + */ + void setNetworkManager(QNetworkAccessManager *manager); + + /** + * Returns the given QNetworkAccessManager. Returns NULL if none is given. + */ + QNetworkAccessManager* networkManager() const; + +Q_SIGNALS: + // This signal will be emitted after each request has got a reply. + // Parameter is the raw response from the service. + void requestReady(QByteArray networkReply); + + void authorizedRequestReady(QByteArray networkReply, int id); + + // This signal will be emited when we have an request tokens available + // (either temporary resource tokens, or authorization tokens). + void receivedToken(QString oauth_token, QString oauth_token_secret); // oauth_token, oauth_token_secret + + // This signal is emited when temporary tokens are returned from the service. + // Note that this signal is also emited in case temporary tokens are not available. + void temporaryTokenReceived(QString oauth_token, QString oauth_token_secret); // oauth_token, oauth_token_secret + + // This signal is emited when the user has authenticated the application to + // communicate with the protected resources. Next we need to exchange the + // temporary tokens for access tokens. + // Note that this signal is also emited if user denies access. + void authorizationReceived(QString oauth_token, QString oauth_verifier); // oauth_token, oauth_verifier + + // This signal is emited when access tokens are received from the service. We are + // ready to start communicating with the protected resources. + void accessTokenReceived(QString oauth_token, QString oauth_token_secret); // oauth_token, oauth_token_secret + + // This signal is emited when the authorized request is done. + // This ends the kQOAuth interactions. + void authorizedRequestDone(); + +private Q_SLOTS: + void onRequestReplyReceived( QNetworkReply *reply ); + void onAuthorizedRequestReplyReceived( QNetworkReply *reply ); + void onVerificationReceived(QMultiMap response); + void onOauth2VerificationReceived(QMultiMap response); + void slotError(QNetworkReply::NetworkError error); + void onSslError(QNetworkReply *reply, const QList &errors); + +private: + KQOAuthManagerPrivate *d_ptr; + Q_DECLARE_PRIVATE(KQOAuthManager); + Q_DISABLE_COPY(KQOAuthManager); + +}; + +#endif // KQOAUTHMANAGER_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager_p.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager_p.h new file mode 100644 index 0000000000..56078dfdf9 --- /dev/null +++ b/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager_p.h @@ -0,0 +1,78 @@ +/** + * KQOAuth - An OAuth authentication library for Qt. + * + * Author: Johan Paul (johan.paul@d-pointer.com) + * http://www.d-pointer.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * KQOAuth is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * In addition, as a special exception, KQOauth provides you certain additional + * rights. These rights are described in the Nokia Qt LGPL Exception + * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + * + * You should have received a copy of the GNU Lesser General Public License + * along with KQOAuth. If not, see + */ +#ifndef KQOAUTHMANAGER_P_H +#define KQOAUTHMANAGER_P_H + +#include "kqoauthauthreplyserver.h" +#include "kqoauthrequest.h" + +class KQOAUTH_EXPORT KQOAuthManagerPrivate { + +public: + KQOAuthManagerPrivate(KQOAuthManager *parent); + ~KQOAuthManagerPrivate(); + + QList< QPair > createQueryParams(const KQOAuthParameters &requestParams); + QMultiMap createTokensFromResponse(QByteArray reply); + bool setSuccessfulRequestToken(const QMultiMap &request); + bool setSuccessfulAuthorized(const QMultiMap &request); + void emitTokens(); + bool setupCallbackServer(); + + KQOAuthManager::KQOAuthError error; + KQOAuthRequest *r; // This request is used to cache the user sent request. + KQOAuthRequest *opaqueRequest; // This request is used to creating opaque convenience requests for the user. + KQOAuthManager * const q_ptr; + + /** + * The items below are needed in order to store the state of the manager and + * by that be able to do convenience operations for the user. + */ + KQOAuthRequest::RequestType currentRequestType; + + // Variables we store here for opaque request handling. + // NOTE: The variables are labeled the same for both access token request + // and protected resource access. + QString requestToken; + QString requestTokenSecret; + QString consumerKey; + QString consumerKeySecret; + QString requestVerifier; + + QString successHtmlFile; + + KQOAuthAuthReplyServer *callbackServer; + + bool hasTemporaryToken; + bool isVerified; + bool isAuthorized; + bool autoAuth; + QNetworkAccessManager *networkManager; + bool managerUserSet; + QMap requestIds; + + Q_DECLARE_PUBLIC(KQOAuthManager); +}; + +#endif // KQOAUTHMANAGER_P_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest.cpp b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest.cpp new file mode 100644 index 0000000000..e81b56dfee --- /dev/null +++ b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest.cpp @@ -0,0 +1,625 @@ +/** + * KQOAuth - An OAuth authentication library for Qt. + * + * Author: Johan Paul (johan.paul@d-pointer.com) + * http://www.d-pointer.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * KQOAuth is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * In addition, as a special exception, KQOauth provides you certain additional + * rights. These rights are described in the Nokia Qt LGPL Exception + * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + * + * You should have received a copy of the GNU Lesser General Public License + * along with KQOAuth. If not, see + */ +#include +#include +#include +#include +#include + +#include +#include + +#include "kqoauthrequest.h" +#include "kqoauthrequest_p.h" +#include "kqoauthutils.h" +#include "kqoauthglobals.h" + + +//////////// Private d_ptr implementation ///////// + +KQOAuthRequestPrivate::KQOAuthRequestPrivate() : + timeout(0) +{ + +} + +KQOAuthRequestPrivate::~KQOAuthRequestPrivate() +{ + +} + +// This method will not include the "oauthSignature" paramater, since it is calculated from these parameters. +void KQOAuthRequestPrivate::prepareRequest() { + + // If parameter list is not empty, we don't want to insert these values by + // accident a second time. So giving up. + if( !requestParameters.isEmpty() ) { + return; + } + + switch ( requestType ) { + case KQOAuthRequest::TemporaryCredentials: + requestParameters.append( qMakePair( OAUTH_KEY_CALLBACK, oauthCallbackUrl.toString()) ); // This is so ugly that it is almost beautiful. + requestParameters.append( qMakePair( OAUTH_KEY_SIGNATURE_METHOD, oauthSignatureMethod) ); + requestParameters.append( qMakePair( OAUTH_KEY_CONSUMER_KEY, oauthConsumerKey )); + requestParameters.append( qMakePair( OAUTH_KEY_VERSION, oauthVersion )); + requestParameters.append( qMakePair( OAUTH_KEY_TIMESTAMP, this->oauthTimestamp() )); + requestParameters.append( qMakePair( OAUTH_KEY_NONCE, this->oauthNonce() )); + break; + + case KQOAuthRequest::AccessToken: + requestParameters.append( qMakePair( OAUTH_KEY_SIGNATURE_METHOD, oauthSignatureMethod )); + requestParameters.append( qMakePair( OAUTH_KEY_CONSUMER_KEY, oauthConsumerKey )); + requestParameters.append( qMakePair( OAUTH_KEY_VERSION, oauthVersion )); + requestParameters.append( qMakePair( OAUTH_KEY_TIMESTAMP, this->oauthTimestamp() )); + requestParameters.append( qMakePair( OAUTH_KEY_NONCE, this->oauthNonce() )); + requestParameters.append( qMakePair( OAUTH_KEY_VERIFIER, oauthVerifier )); + requestParameters.append( qMakePair( OAUTH_KEY_TOKEN, oauthToken )); + break; + + case KQOAuthRequest::AuthorizedRequest: + requestParameters.append( qMakePair( OAUTH_KEY_SIGNATURE_METHOD, oauthSignatureMethod )); + requestParameters.append( qMakePair( OAUTH_KEY_CONSUMER_KEY, oauthConsumerKey )); + requestParameters.append( qMakePair( OAUTH_KEY_VERSION, oauthVersion )); + requestParameters.append( qMakePair( OAUTH_KEY_TIMESTAMP, this->oauthTimestamp() )); + requestParameters.append( qMakePair( OAUTH_KEY_NONCE, this->oauthNonce() )); + requestParameters.append( qMakePair( OAUTH_KEY_TOKEN, oauthToken )); + break; + + default: + break; + } +} + +void KQOAuthRequestPrivate::signRequest() { + QString signature = this->oauthSignature(); + requestParameters.append( qMakePair( OAUTH_KEY_SIGNATURE, signature) ); +} + +QString KQOAuthRequestPrivate::oauthSignature() { + /** + * http://oauth.net/core/1.0/#anchor16 + * The HMAC-SHA1 signature method uses the HMAC-SHA1 signature algorithm as defined in [RFC2104] where the + * Signature Base String is the text and the key is the concatenated values (each first encoded per Parameter + * Encoding) of the Consumer Secret and Token Secret, separated by an ‘&’ character (ASCII code 38) even if empty. + **/ + QByteArray baseString = this->requestBaseString(); + + QString secret = QString(QUrl::toPercentEncoding(oauthConsumerSecretKey)) + "&" + QString(QUrl::toPercentEncoding(oauthTokenSecret)); + QString signature = KQOAuthUtils::hmac_sha1(baseString, secret); + + if (debugOutput) { + qDebug() << "========== KQOAuthRequest has the following signature:"; + qDebug() << " * Signature : " << QUrl::toPercentEncoding(signature) << "\n"; + } + return QString( QUrl::toPercentEncoding(signature) ); +} + +bool normalizedParameterSort(const QPair &left, const QPair &right) { + QString keyLeft = left.first; + QString valueLeft = left.second; + QString keyRight = right.first; + QString valueRight = right.second; + + if(keyLeft == keyRight) { + return (valueLeft < valueRight); + } else { + return (keyLeft < keyRight); + } +} +QByteArray KQOAuthRequestPrivate::requestBaseString() { + QByteArray baseString; + + // Every request has these as the commont parameters. + baseString.append( oauthHttpMethodString.toUtf8() + "&"); // HTTP method + baseString.append( QUrl::toPercentEncoding( oauthRequestEndpoint.toString(QUrl::RemoveQuery) ) + "&" ); // The path and query components + + QList< QPair > baseStringParameters; + baseStringParameters.append(requestParameters); + baseStringParameters.append(additionalParameters); + + // Sort the request parameters. These parameters have been + // initialized earlier. + qSort(baseStringParameters.begin(), + baseStringParameters.end(), + normalizedParameterSort + ); + + // Last append the request parameters correctly encoded. + baseString.append( encodedParamaterList(baseStringParameters) ); + + if (debugOutput) { + qDebug() << "========== KQOAuthRequest has the following base string:"; + qDebug() << baseString << "\n"; + } + + return baseString; +} + +QByteArray KQOAuthRequestPrivate::encodedParamaterList(const QList< QPair > ¶meters) { + QByteArray resultList; + + bool first = true; + QPair parameter; + + // Do the debug output. + if (debugOutput) { + qDebug() << "========== KQOAuthRequest has the following parameters:"; + } + foreach (parameter, parameters) { + if(!first) { + resultList.append( "&" ); + } else { + first = false; + } + + // Here we don't need to explicitely encode the strings to UTF-8 since + // QUrl::toPercentEncoding() takes care of that for us. + resultList.append( QUrl::toPercentEncoding(parameter.first) // Parameter key + + "=" + + QUrl::toPercentEncoding(parameter.second) // Parameter value + ); + if (debugOutput) { + qDebug() << " * " + << parameter.first + << " : " + << parameter.second; + } + } + if (debugOutput) { + qDebug() << "\n"; + } + + return QUrl::toPercentEncoding(resultList); +} + +QString KQOAuthRequestPrivate::oauthTimestamp() const { + // This is basically for unit tests only. In most cases we don't set the nonce beforehand. + if (!oauthTimestamp_.isEmpty()) { + return oauthTimestamp_; + } + +#if QT_VERSION >= 0x040700 + return QString::number(QDateTime::currentDateTimeUtc().toTime_t()); +#else + return QString::number(QDateTime::currentDateTime().toUTC().toTime_t()); +#endif + +} + +QString KQOAuthRequestPrivate::oauthNonce() const { + // This is basically for unit tests only. In most cases we don't set the nonce beforehand. + return QString::number(qrand()); +} + +bool KQOAuthRequestPrivate::validateRequest() const { + switch ( requestType ) { + case KQOAuthRequest::TemporaryCredentials: + if (oauthRequestEndpoint.isEmpty() + || oauthConsumerKey.isEmpty() + || oauthNonce_.isEmpty() + || oauthSignatureMethod.isEmpty() + || oauthTimestamp_.isEmpty() + || oauthVersion.isEmpty()) + { + return false; + } + return true; + + case KQOAuthRequest::AccessToken: + if (oauthRequestEndpoint.isEmpty() + || oauthVerifier.isEmpty() + || oauthConsumerKey.isEmpty() + || oauthNonce_.isEmpty() + || oauthSignatureMethod.isEmpty() + || oauthTimestamp_.isEmpty() + || oauthToken.isEmpty() + || oauthTokenSecret.isEmpty() + || oauthVersion.isEmpty()) + { + return false; + } + return true; + + case KQOAuthRequest::AuthorizedRequest: + if(requestOAuthMethod == KQOAuthRequest::OAUTH1) { + if (oauthRequestEndpoint.isEmpty() + || oauthConsumerKey.isEmpty() + || oauthNonce_.isEmpty() + || oauthSignatureMethod.isEmpty() + || oauthTimestamp_.isEmpty() + || oauthToken.isEmpty() + || oauthTokenSecret.isEmpty() + || oauthVersion.isEmpty()) + { + return false; + } + return true; + } else { + if(oauthToken.isEmpty()){ + return false; + } + return true; + } + + default: + return false; + } + + // We should not come here. + return false; +} + +//////////// Public implementation //////////////// + +KQOAuthRequest::KQOAuthRequest(QObject *parent) : + QObject(parent), + d_ptr(new KQOAuthRequestPrivate) +{ + d_ptr->debugOutput = false; // No debug output by default. + qsrand(QTime::currentTime().msec()); // We need to seed the nonce random number with something. + // However, we cannot do this while generating the nonce since + // we might get the same seed. So initializing here should be fine. +} + +KQOAuthRequest::~KQOAuthRequest() +{ + delete d_ptr; +} + +void KQOAuthRequest::initRequest(KQOAuthRequest::RequestType type, const QUrl &requestEndpoint) { + Q_D(KQOAuthRequest); + + if (!requestEndpoint.isValid()) { + qWarning() << "Endpoint URL is not valid. Ignoring. This request might not work."; + return; + } + + if (type < 0 || type > KQOAuthRequest::AuthorizedRequest) { + qWarning() << "Invalid request type. Ignoring. This request might not work."; + return; + } + + // Clear the request + clearRequest(); + + // Set smart defaults. + d->requestType = type; + d->oauthRequestEndpoint = requestEndpoint; + d->oauthTimestamp_ = d->oauthTimestamp(); + d->oauthNonce_ = d->oauthNonce(); + this->setSignatureMethod(KQOAuthRequest::HMAC_SHA1); + this->setHttpMethod(KQOAuthRequest::POST); + this->setRequestOAuthMethod(KQOAuthRequest::OAUTH1); + d->oauthVersion = "1.0"; // Currently supports only version 1.0 + + d->contentType = "application/x-www-form-urlencoded"; +} + +void KQOAuthRequest::setConsumerKey(const QString &consumerKey) { + Q_D(KQOAuthRequest); + d->oauthConsumerKey = consumerKey; +} + +void KQOAuthRequest::setConsumerSecretKey(const QString &consumerSecretKey) { + Q_D(KQOAuthRequest); + d->oauthConsumerSecretKey = consumerSecretKey; +} + +void KQOAuthRequest::setCallbackUrl(const QUrl &callbackUrl) { + Q_D(KQOAuthRequest); + + d->oauthCallbackUrl = callbackUrl; +} + +void KQOAuthRequest::setSignatureMethod(KQOAuthRequest::RequestSignatureMethod requestMethod) { + Q_D(KQOAuthRequest); + QString requestMethodString; + + switch (requestMethod) { + case KQOAuthRequest::PLAINTEXT: + requestMethodString = "PLAINTEXT"; + break; + case KQOAuthRequest::HMAC_SHA1: + requestMethodString = "HMAC-SHA1"; + break; + case KQOAuthRequest::RSA_SHA1: + requestMethodString = "RSA-SHA1"; + break; + default: + // We should not come here + qWarning() << "Invalid signature method set."; + break; + } + + d->oauthSignatureMethod = requestMethodString; +} + +void KQOAuthRequest::setTokenSecret(const QString &tokenSecret) { + Q_D(KQOAuthRequest); + + d->oauthTokenSecret = tokenSecret; +} + +void KQOAuthRequest::setToken(const QString &token) { + Q_D(KQOAuthRequest); + + d->oauthToken = token; +} + +void KQOAuthRequest::setVerifier(const QString &verifier) { + Q_D(KQOAuthRequest); + + d->oauthVerifier = verifier; +} + + +void KQOAuthRequest::setHttpMethod(KQOAuthRequest::RequestHttpMethod httpMethod) { + Q_D(KQOAuthRequest); + + QString requestHttpMethodString; + + switch (httpMethod) { + case KQOAuthRequest::GET: + requestHttpMethodString = "GET"; + break; + case KQOAuthRequest::POST: + requestHttpMethodString = "POST"; + break; + default: + qWarning() << "Invalid HTTP method set."; + break; + } + + d->oauthHttpMethod = httpMethod; + d->oauthHttpMethodString = requestHttpMethodString; +} + +void KQOAuthRequest::setRequestOAuthMethod(KQOAuthRequest::RequestOAuthMethod oauthMethod) { + Q_D(KQOAuthRequest); + + d->requestOAuthMethod = oauthMethod; +} + +KQOAuthRequest::RequestHttpMethod KQOAuthRequest::httpMethod() const { + Q_D(const KQOAuthRequest); + + return d->oauthHttpMethod; +} + +KQOAuthRequest::RequestOAuthMethod KQOAuthRequest::oauthMethod() const { + Q_D(const KQOAuthRequest); + + return d->requestOAuthMethod; +} + +void KQOAuthRequest::setAdditionalParameters(const KQOAuthParameters &additionalParams) { + Q_D(KQOAuthRequest); + + QList additionalKeys = additionalParams.keys(); + QList additionalValues = additionalParams.values(); + + int i=0; + foreach(QString key, additionalKeys) { + QString value = additionalValues.at(i); + d->additionalParameters.append( qMakePair(key, value) ); + i++; + } +} + +KQOAuthParameters KQOAuthRequest::additionalParameters() const { + Q_D(const KQOAuthRequest); + + QMultiMap additionalParams; + for(int i=0; iadditionalParameters.size(); i++) { + additionalParams.insert(d->additionalParameters.at(i).first, + d->additionalParameters.at(i).second); + } + if(d->requestOAuthMethod == KQOAuthRequest::OAUTH2) { + additionalParams.insert(OAUTH_KEY_TOKEN, d->oauthToken); + } + + return additionalParams; +} + +KQOAuthRequest::RequestType KQOAuthRequest::requestType() const { + Q_D(const KQOAuthRequest); + return d->requestType; +} + +QUrl KQOAuthRequest::requestEndpoint() const { + Q_D(const KQOAuthRequest); + return d->oauthRequestEndpoint; +} + +QList KQOAuthRequest::requestParameters() { + Q_D(KQOAuthRequest); + + QList requestParamList; + + d->prepareRequest(); + if (!isValid() ) { + qWarning() << "Request is not valid! I will still sign it, but it will probably not work."; + } + if(d->requestOAuthMethod != KQOAuthRequest::OAUTH2) { + d->signRequest(); + } + + QPair requestParam; + QString param; + QString value; + foreach (requestParam, d->requestParameters) { + param = requestParam.first; + value = requestParam.second; + requestParamList.append(QString(param + "=\"" + value +"\"").toUtf8()); + } + + return requestParamList; +} + +QString KQOAuthRequest::contentType() +{ + Q_D(const KQOAuthRequest); + return d->contentType; +} + +void KQOAuthRequest::setContentType(const QString &contentType) +{ + Q_D(KQOAuthRequest); + d->contentType = contentType; +} + +QByteArray KQOAuthRequest::rawData() +{ + Q_D(const KQOAuthRequest); + return d->postRawData; +} + +void KQOAuthRequest::setRawData(const QByteArray &rawData) +{ + Q_D(KQOAuthRequest); + d->postRawData = rawData; +} + +QByteArray KQOAuthRequest::requestBody() const { + Q_D(const KQOAuthRequest); + + QByteArray postBodyContent; + bool first = true; + for(int i=0; i < d->additionalParameters.size(); i++) { + if(!first) { + postBodyContent.append("&"); + } else { + first = false; + } + + QString key = d->additionalParameters.at(i).first; + QString value = d->additionalParameters.at(i).second; + + postBodyContent.append(QUrl::toPercentEncoding(key) + QString("=").toUtf8() + + QUrl::toPercentEncoding(value)); + } + qDebug() << postBodyContent; + return postBodyContent; +} + +bool KQOAuthRequest::isValid() const { + Q_D(const KQOAuthRequest); + + return d->validateRequest(); +} + +void KQOAuthRequest::setTimeout(int timeoutMilliseconds) { + Q_D(KQOAuthRequest); + d->timeout = timeoutMilliseconds; +} + +void KQOAuthRequest::clearRequest() { + Q_D(KQOAuthRequest); + + d->oauthRequestEndpoint = ""; + d->oauthHttpMethodString = ""; + d->oauthConsumerKey = ""; + d->oauthConsumerSecretKey = ""; + d->oauthToken = ""; + d->oauthTokenSecret = ""; + d->oauthSignatureMethod = ""; + d->oauthCallbackUrl = ""; + d->oauthVerifier = ""; + d->oauthTimestamp_ = ""; + d->oauthNonce_ = ""; + d->requestParameters.clear(); + d->additionalParameters.clear(); + d->timeout = 0; +} + +void KQOAuthRequest::setEnableDebugOutput(bool enabled) { + Q_D(KQOAuthRequest); + d->debugOutput = enabled; +} + +/** + * Protected implementations for inherited classes + */ +bool KQOAuthRequest::validateXAuthRequest() const { + Q_D(const KQOAuthRequest); + + if (d->oauthRequestEndpoint.isEmpty() + || d->oauthConsumerKey.isEmpty() + || d->oauthNonce_.isEmpty() + || d->oauthSignatureMethod.isEmpty() + || d->oauthTimestamp_.isEmpty() + || d->oauthVersion.isEmpty()) + { + return false; + } + return true; +} + +bool KQOAuthRequest::validateOauth2Request() const { + Q_D(const KQOAuthRequest); + + if (d->oauthRequestEndpoint.isEmpty() || d->oauthToken.isEmpty()) + { + return false; + } + return true; +} + + +/** + * Private implementations for friend classes + */ +QString KQOAuthRequest::consumerKeyForManager() const { + Q_D(const KQOAuthRequest); + return d->oauthConsumerKey; +} + +QString KQOAuthRequest::consumerKeySecretForManager() const { + Q_D(const KQOAuthRequest); + return d->oauthConsumerSecretKey; +} + +QUrl KQOAuthRequest::callbackUrlForManager() const { + Q_D(const KQOAuthRequest); + return d->oauthCallbackUrl; +} + +void KQOAuthRequest::requestTimerStart() +{ + Q_D(KQOAuthRequest); + if (d->timeout > 0) { + connect(&(d->timer), SIGNAL(timeout()), this, SIGNAL(requestTimedout())); + d->timer.start(d->timeout); + } +} + +void KQOAuthRequest::requestTimerStop() +{ + Q_D(KQOAuthRequest); + if (d->timeout > 0) { + disconnect(&(d->timer), SIGNAL(timeout()), this, SIGNAL(requestTimedout())); + d->timer.stop(); + } +} diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest.h new file mode 100644 index 0000000000..616003db73 --- /dev/null +++ b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest.h @@ -0,0 +1,157 @@ +/** + * KQOAuth - An OAuth authentication library for Qt. + * + * Author: Johan Paul (johan.paul@d-pointer.com) + * http://www.d-pointer.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * KQOAuth is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * In addition, as a special exception, KQOauth provides you certain additional + * rights. These rights are described in the Nokia Qt LGPL Exception + * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + * + * You should have received a copy of the GNU Lesser General Public License + * along with KQOAuth. If not, see + */ +#ifndef KQOAUTHREQUEST_H +#define KQOAUTHREQUEST_H + +#include +#include +#include + +#include "kqoauthglobals.h" + +typedef QMultiMap KQOAuthParameters; + +class KQOAuthRequestPrivate; +class KQOAUTH_EXPORT KQOAuthRequest : public QObject +{ + Q_OBJECT +public: + explicit KQOAuthRequest(QObject *parent = 0); + ~KQOAuthRequest(); + + enum RequestType { + TemporaryCredentials = 0, + AccessToken, + AuthorizedRequest + }; + + enum RequestSignatureMethod { + PLAINTEXT = 0, + HMAC_SHA1, + RSA_SHA1 + }; + + enum RequestHttpMethod { + GET = 0, + POST + }; + + enum RequestOAuthMethod { + OAUTH1 = 0, + OAUTH2 + }; + + /** + * These methods can be overridden in child classes which are different types of + * OAuth requests. + */ + // Validate the request of this type. + virtual bool isValid() const; + + /** + * These methods are OAuth request type specific and not overridden in child + * classes. + * NOTE: Refactorting still a TODO + */ + // Initialize the request of this type. + virtual void initRequest(KQOAuthRequest::RequestType type, const QUrl &requestEndpoint); + + void setConsumerKey(const QString &consumerKey); + void setConsumerSecretKey(const QString &consumerSecretKey); + + // Mandatory methods for acquiring a request token + void setCallbackUrl(const QUrl &callbackUrl); + + // Mandator methods for acquiring a access token + void setTokenSecret(const QString &tokenSecret); + void setToken(const QString &token); + void setVerifier(const QString &verifier); + + // Request signature method to use - HMAC_SHA1 currently only supported + void setSignatureMethod(KQOAuthRequest::RequestSignatureMethod = KQOAuthRequest::HMAC_SHA1); + + // Request's HTTP method. + void setHttpMethod(KQOAuthRequest::RequestHttpMethod = KQOAuthRequest::POST); + KQOAuthRequest::RequestHttpMethod httpMethod() const; + KQOAuthRequest::RequestOAuthMethod oauthMethod() const; + void setRequestOAuthMethod(KQOAuthRequest::RequestOAuthMethod = KQOAuthRequest::OAUTH1); + + // Sets the timeout for this request. If the timeout expires, signal "requestTimedout" will be + // emitted from the manager. + // 0 = If set to zero, timeout is disabled. + // TODO: Do we need some request ID now? + void setTimeout(int timeoutMilliseconds); + + // Additional optional parameters to the request. + void setAdditionalParameters(const KQOAuthParameters &additionalParams); + KQOAuthParameters additionalParameters() const; + QList requestParameters(); // This will return all request's parameters in the raw format given + // to the QNetworkRequest. + QByteArray requestBody() const; // This will return the POST body as given to the QNetworkRequest. + + KQOAuthRequest::RequestType requestType() const; + QUrl requestEndpoint() const; + + void setContentType(const QString &contentType); + QString contentType(); + + void setRawData(const QByteArray &rawData); + QByteArray rawData(); + + void clearRequest(); + + // Enable verbose debug output for request content. + void setEnableDebugOutput(bool enabled); + +Q_SIGNALS: + // This signal is emited if the request is not completed before the request's timeout + // value has expired. + void requestTimedout(); + +protected: + bool validateXAuthRequest() const; + bool validateOauth2Request() const; + +private: + KQOAuthRequestPrivate * const d_ptr; + Q_DECLARE_PRIVATE(KQOAuthRequest); + Q_DISABLE_COPY(KQOAuthRequest); + + // These classes are only for the internal use of KQOAuthManager so it can + // work with the opaque request. + QString consumerKeyForManager() const; + QString consumerKeySecretForManager() const; + QUrl callbackUrlForManager() const; + + // This method is for timeout handling by the KQOAuthManager. + void requestTimerStart(); + void requestTimerStop(); + + friend class KQOAuthManager; +#ifdef UNIT_TEST + friend class Ut_KQOAuth; +#endif +}; + +#endif // KQOAUTHREQUEST_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_1.cpp b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_1.cpp new file mode 100644 index 0000000000..165eb3c23d --- /dev/null +++ b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_1.cpp @@ -0,0 +1,5 @@ +#include "kqoauthrequest_1.h" + +KQOAuthRequest_1::KQOAuthRequest_1() +{ +} diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_1.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_1.h new file mode 100644 index 0000000000..8da5df8f4b --- /dev/null +++ b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_1.h @@ -0,0 +1,12 @@ +#ifndef KQOAUTHREQUEST_1_H +#define KQOAUTHREQUEST_1_H + +#include "kqoauthrequest.h" + +class KQOAUTH_EXPORT KQOAuthRequest_1 : public KQOAuthRequest +{ +public: + KQOAuthRequest_1(); +}; + +#endif // KQOAUTHREQUEST_1_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_p.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_p.h new file mode 100644 index 0000000000..22be4ef7eb --- /dev/null +++ b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_p.h @@ -0,0 +1,98 @@ +/** + * KQOAuth - An OAuth authentication library for Qt. + * + * Author: Johan Paul (johan.paul@d-pointer.com) + * http://www.d-pointer.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * KQOAuth is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * In addition, as a special exception, KQOauth provides you certain additional + * rights. These rights are described in the Nokia Qt LGPL Exception + * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + * + * You should have received a copy of the GNU Lesser General Public License + * along with KQOAuth. If not, see + */ +#ifndef KQOAUTHREQUEST_P_H +#define KQOAUTHREQUEST_P_H +#include "kqoauthglobals.h" +#include "kqoauthrequest.h" + +#include +#include +#include +#include +#include +#include + +class KQOAUTH_EXPORT KQOAuthRequestPrivate { + +public: + KQOAuthRequestPrivate(); + ~KQOAuthRequestPrivate(); + + // Helper methods to get the values for the OAuth request parameters. + QString oauthTimestamp() const; + QString oauthNonce() const; + QString oauthSignature(); + + // Utility methods for making the request happen. + void prepareRequest(); + void signRequest(); + bool validateRequest() const; + QByteArray requestBaseString(); + QByteArray encodedParamaterList(const QList< QPair > &requestParameters); + void insertAdditionalParams(); + void insertPostBody(); + + QUrl oauthRequestEndpoint; + KQOAuthRequest::RequestHttpMethod oauthHttpMethod; + QString oauthHttpMethodString; + QString oauthConsumerKey; + QString oauthConsumerSecretKey; + QString oauthToken; + QString oauthTokenSecret; + QString oauthSignatureMethod; + QUrl oauthCallbackUrl; + QString oauthVersion; + QString oauthVerifier; + + // These will be generated by the helper methods + QString oauthTimestamp_; + QString oauthNonce_; + + // User specified additional parameters needed for the request. + QList< QPair > additionalParameters; + + // The raw POST body content as given to the HTTP request. + QByteArray postBodyContent; + + // Protocol parameters. + // These parameters are used in the "Authorized" header of the HTTP request. + QList< QPair > requestParameters; + + KQOAuthRequest::RequestType requestType; + KQOAuthRequest::RequestOAuthMethod requestOAuthMethod; + + //The Content-Type HTTP header + QString contentType; + + //Raw data to post if type is not url-encoded + QByteArray postRawData; + + // Timeout for this request in milliseconds. + int timeout; + QTimer timer; + + bool debugOutput; + +}; +#endif // KQOAUTHREQUEST_P_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth.cpp b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth.cpp new file mode 100644 index 0000000000..9f6a8593da --- /dev/null +++ b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth.cpp @@ -0,0 +1,95 @@ +/** + * KQOAuth - An OAuth authentication library for Qt. + * + * Author: Johan Paul (johan.paul@d-pointer.com) + * http://www.d-pointer.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * KQOAuth is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * In addition, as a special exception, KQOauth provides you certain additional + * rights. These rights are described in the Nokia Qt LGPL Exception + * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + * + * You should have received a copy of the GNU Lesser General Public License + * along with KQOAuth. If not, see + */ +#include + +#include "kqoauthrequest_xauth_p.h" +#include "kqoauthrequest_xauth.h" + +/** + * Private d_ptr implementations. + */ +KQOAuthRequest_XAuthPrivate::KQOAuthRequest_XAuthPrivate() +{ + +} + +KQOAuthRequest_XAuthPrivate::~KQOAuthRequest_XAuthPrivate() +{ +} + +/** + * Public implementations. + */ +KQOAuthRequest_XAuth::KQOAuthRequest_XAuth(QObject *parent) : + KQOAuthRequest(parent), + d_ptr(new KQOAuthRequest_XAuthPrivate) +{ +} + +bool KQOAuthRequest_XAuth::isValid() const { + // An xAuth can never request temporary credentials. + if (requestType() == KQOAuthRequest::TemporaryCredentials) { + qWarning() << "XAuth request cannot be of type KQOAuthRequest::TemporaryCredentials. Aborting."; + return false; + } + + // Access token must always be retrieved using the POST HTTP method. + if (requestType() == KQOAuthRequest::AccessToken + && httpMethod() != KQOAuthRequest::POST) { + + qWarning() << "Access tokens must be fetched using the POST HTTP method. Aborting."; + + return false; + } + + if (!xauth_parameters_set) { + qWarning() << "No XAuth parameters set. Aborting."; + return false; + } + + // And then check the validity of the XAuth request. + // Provided by the base class as a protected method for us. + return validateXAuthRequest(); +} + +void KQOAuthRequest_XAuth::setXAuthLogin(const QString &username, + const QString &password) { + + if (username.isEmpty() || password.isEmpty()) { + qWarning() << "Username or password cannot be empty. Aborting."; + return; + } + + xauth_parameters_set = true; + + qDebug() << username << password; + + KQOAuthParameters xauthParams; + xauthParams.insert("x_auth_username", username); + xauthParams.insert("x_auth_password", password); + xauthParams.insert("x_auth_mode", "client_auth"); + + setAdditionalParameters(xauthParams); +} + diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth.h new file mode 100644 index 0000000000..93539cb785 --- /dev/null +++ b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth.h @@ -0,0 +1,53 @@ +/** + * KQOAuth - An OAuth authentication library for Qt. + * + * Author: Johan Paul (johan.paul@d-pointer.com) + * http://www.d-pointer.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * KQOAuth is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * In addition, as a special exception, KQOauth provides you certain additional + * rights. These rights are described in the Nokia Qt LGPL Exception + * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + * + * You should have received a copy of the GNU Lesser General Public License + * along with KQOAuth. If not, see + */ +#ifndef KQOAUTHREQUEST_XAUTH_H +#define KQOAUTHREQUEST_XAUTH_H + +#include "kqoauthrequest.h" +#include "kqoauthrequest_1.h" + +class KQOAuthRequest_XAuthPrivate; +class KQOAUTH_EXPORT KQOAuthRequest_XAuth : public KQOAuthRequest +{ + Q_OBJECT +public: + KQOAuthRequest_XAuth(QObject *parent = 0); + + /** + * These methods can be overridden in child classes which are different types of + * OAuth requests. + */ + // Validate the request of this type. + bool isValid() const; + + // Give the xAuth specific parameters. + void setXAuthLogin(const QString &username = "", + const QString &password = ""); + +private: + KQOAuthRequest_XAuthPrivate * const d_ptr; + bool xauth_parameters_set; +}; + +#endif // KQOAUTHREQUEST_XAUTH_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth_p.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth_p.h new file mode 100644 index 0000000000..9f79d31ef8 --- /dev/null +++ b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth_p.h @@ -0,0 +1,14 @@ +#ifndef KQOAUTHREQUEST_XAUTH_P_H +#define KQOAUTHREQUEST_XAUTH_P_H + +#include "kqoauthglobals.h" + +class KQOAuthRequest; +class KQOAUTH_EXPORT KQOAuthRequest_XAuthPrivate +{ +public: + KQOAuthRequest_XAuthPrivate(); + ~KQOAuthRequest_XAuthPrivate(); +}; + +#endif // KQOAUTHREQUEST_XAUTH_P_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthutils.cpp b/src/libtomahawk/thirdparty/kqoauth/kqoauthutils.cpp new file mode 100644 index 0000000000..d021385ef8 --- /dev/null +++ b/src/libtomahawk/thirdparty/kqoauth/kqoauthutils.cpp @@ -0,0 +1,83 @@ +/** + * KQOAuth - An OAuth authentication library for Qt. + * + * Author: Johan Paul (johan.paul@d-pointer.com) + * http://www.d-pointer.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * KQOAuth is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * In addition, as a special exception, KQOauth provides you certain additional + * rights. These rights are described in the Nokia Qt LGPL Exception + * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + * + * You should have received a copy of the GNU Lesser General Public License + * along with KQOAuth. If not, see + */ +#include +#include +#include + +#include +#include "kqoauthutils.h" + +QString KQOAuthUtils::hmac_sha1(const QString &message, const QString &key) +{ + QByteArray keyBytes = key.toAscii(); + int keyLength; // Lenght of key word + const int blockSize = 64; // Both MD5 and SHA-1 have a block size of 64. + + keyLength = keyBytes.size(); + // If key is longer than block size, we need to hash the key + if (keyLength > blockSize) { + QCryptographicHash hash(QCryptographicHash::Sha1); + hash.addData(keyBytes); + keyBytes = hash.result(); + } + + /* http://tools.ietf.org/html/rfc2104 - (1) */ + // Create the opad and ipad for the hash function. + QByteArray ipad; + QByteArray opad; + + ipad.fill( 0, blockSize); + opad.fill( 0, blockSize); + + ipad.replace(0, keyBytes.length(), keyBytes); + opad.replace(0, keyBytes.length(), keyBytes); + + /* http://tools.ietf.org/html/rfc2104 - (2) & (5) */ + for (int i=0; i<64; i++) { + ipad[i] = ipad[i] ^ 0x36; + opad[i] = opad[i] ^ 0x5c; + } + + QByteArray workArray; + workArray.clear(); + + workArray.append(ipad, 64); + /* http://tools.ietf.org/html/rfc2104 - (3) */ + workArray.append(message.toAscii()); + + + /* http://tools.ietf.org/html/rfc2104 - (4) */ + QByteArray sha1 = QCryptographicHash::hash(workArray, QCryptographicHash::Sha1); + + /* http://tools.ietf.org/html/rfc2104 - (6) */ + workArray.clear(); + workArray.append(opad, 64); + workArray.append(sha1); + + sha1.clear(); + + /* http://tools.ietf.org/html/rfc2104 - (7) */ + sha1 = QCryptographicHash::hash(workArray, QCryptographicHash::Sha1); + return QString(sha1.toBase64()); +} diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthutils.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthutils.h new file mode 100644 index 0000000000..db1f8840fd --- /dev/null +++ b/src/libtomahawk/thirdparty/kqoauth/kqoauthutils.h @@ -0,0 +1,37 @@ +/** + * KQOAuth - An OAuth authentication library for Qt. + * + * Author: Johan Paul (johan.paul@d-pointer.com) + * http://www.d-pointer.com + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * KQOAuth is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * In addition, as a special exception, KQOauth provides you certain additional + * rights. These rights are described in the Nokia Qt LGPL Exception + * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + * + * You should have received a copy of the GNU Lesser General Public License + * along with KQOAuth. If not, see + */ +#ifndef KQOAUTHUTILS_H +#define KQOAUTHUTILS_H + +#include "kqoauthglobals.h" + +class QString; +class KQOAUTH_EXPORT KQOAuthUtils +{ +public: + + static QString hmac_sha1(const QString &message, const QString &key); +}; + +#endif // KQOAUTHUTILS_H From abaaf03a9a339245861fb0cfaa8952f21bd9cc46 Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Sun, 10 Feb 2013 18:42:09 +0100 Subject: [PATCH 02/76] Add empty Dropbox account manager and config ui. --- data/images/dropbox-icon.png | Bin 0 -> 13041 bytes data/images/dropbox-icon.svg | 1584 +++++++++++++++++ resources.qrc | 1 + src/TomahawkApp.cpp | 4 + src/libtomahawk/CMakeLists.txt | 4 + .../accounts/dropbox/DropboxAccount.cpp | 272 +++ .../accounts/dropbox/DropboxAccount.h | 105 ++ .../accounts/dropbox/DropboxConfig.cpp | 73 + .../accounts/dropbox/DropboxConfig.h | 61 + .../accounts/dropbox/DropboxConfig.ui | 101 ++ src/libtomahawk/utils/TomahawkUtils.h | 1 + src/libtomahawk/utils/TomahawkUtilsGui.cpp | 3 + 12 files changed, 2209 insertions(+) create mode 100644 data/images/dropbox-icon.png create mode 100644 data/images/dropbox-icon.svg create mode 100644 src/libtomahawk/accounts/dropbox/DropboxAccount.cpp create mode 100644 src/libtomahawk/accounts/dropbox/DropboxAccount.h create mode 100644 src/libtomahawk/accounts/dropbox/DropboxConfig.cpp create mode 100644 src/libtomahawk/accounts/dropbox/DropboxConfig.h create mode 100644 src/libtomahawk/accounts/dropbox/DropboxConfig.ui diff --git a/data/images/dropbox-icon.png b/data/images/dropbox-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ebde4d0729a45dd4e169aac69203f68f107d8473 GIT binary patch literal 13041 zcmVd7NBTnfHIsxl8SPS9SH?ouspGKnR2_2yVcjgMy60=;(~= zxS;Z?2ngbepbR53qvNQfBO>5}V%Q8zLKa9!$lghMU(##!TI;R4_n!BUTerKq)17oD zy@%)XsdT04*1hLE=X;;~oO7P@907Aeh{=JH_5Qbg?A!j!Z@pcQ_v)Gc&RXbNdZtS@ z=|UvRd8O;~-u15!xmI3vi=OOHssmlk;5;+aMLV4cGhKkw2{Gn$F1hS|`R}{)Tj48j zc}L!&^UH;b3op`R5w5fz+Y8RsnJ(ib3fW3lUR!YUx4xTy`9ECcTYAYdvFyA{plddz z?RX8>)aXnX@KiF3VIn3vybFTw{PZ_Ne}Bgp3zw~{Twfpy%Y8&KOTfh|HmpY`=}I*n z+Q)S*G1H|zYatRGi`L&#^2z^xD6sg#Wy}1MQ0yS$?y#2@UUHEoRK6zNdbCwd^tAxc zXS%qf$*hElS?nR#ijB7v{qukRBLDK6uUb~%b6i%y5V8{NBB9((;IhM#EWd2M7${w% zG#{$b68$G;y4+_f%<2gHFZ`6obRmim z10LG~CtzU!%=!{#{{nWAkZ&W{WJ$~f7njP*uinU${qA&ELoL@bQOp7>H5*_Otp$~r z=gzba^2hi;(3$ulnUZpEBF?Hg| zesHeLaJ^0?%wBQ+bw#({|L=Jhy>DZMM-ocx#tkwA(r}oJ`T`*vA#7*FY;Ff%`p!!& z#mleIV%^D1cXK^BpV8j!jKV~s=NIYq zG<;sA;0&x#T8|x9V?FJd;qJ6x_ml;${HHq#Z@TyM0e`?*?jW)<|> zq0j+xS|uUlEe(pRu6-wTHK_Ksc4&!cJEqZ>npT)3cksf(4}I^Uz&k#9YhiI&-ZC$t zz(x>EUjb(a6JXr2B`&}r5jx#VOU3-f=V#iFcVzlHsxd=Os^|(V&A4Ttz{)=K6Pu z4(|%Jr=?Ae_f5HVo?4iQY_`(XZ!fs%-XG<^^HU!P2Se_~9-^QnM_HI$m`sHOfZswW zauOwAl~W5gZs4f_o6=r=kgMq_cg%^24%hOHA1b`{{s#g})>jtVhk|j{Lyox851P>7G0CR$RWa!Yd0U zcEFx9_&Aj?nO4dp6DmA}7}+h+qKnR#thNP-n%z6HV>44#d&zt8`@ddv%l%*T6)!0+ zv4b3JMA@ebrmS+U0#M`xf>uJxRp{3jTz0AC3$IXG4%ca^_>}lklMWM!vddn&>fMF6 z-2b!uYd`z`{9w?t)D8F~3?F=)V#}0!POAtk^$|$2O8tcwuat^bT%pwOIie=|+c3GN zp9H(NByiQozEk$mfBUl6?RFGfL6TW;z3KpUVo$7 zSrb>Ikrtj&Vv|_+$%RR)H{N?kaPfr;OB_T+Hb5eC+$gIIOfO7;q1aL< z!6_3utfgUAvgRVK{a9DJXY!^bM0apy!TaufF!=V5zdz4mm4Xr<>Rg!hm`0dP>nt#! z#7PL*fVAwfWh$?}LiUE2s~xqSYOJ?@vg$u6Fp(%Zt%b|pUGmTW{^Pt$|KYm)P`;M1wvv1-y8LpjXw67#J_kIK9=asiq#n9TA3$afGb+=Qs;btWs{d9}bb zzjC7Lu&$;DCaM5pqRqMD$`6-+^1pxVTXNCzuuWu6#xd$p2WAE)^SU5FVuS@ALYYTo zsy*OIFT3V#aR)8OX-JQkqL4Ok>ehzD1cvy!!!Kv(VQ_L}2d%bbxfHF21TM8V-J4PAHJ zzZLz%x4!6GuzF#UU0{BZLn8B#*$tCvq3j~C*he6XUGB|Wy-e_ztV}l_JfV>)7y zm*BF9LWg(NB388WGPUJ!b-KT!31js1L{I+eg7@F`!@#>ge@mXvWA_Psuv#FIab3reSwuCf3`CaSWlH7A9tO z6}#8G`{U)G_~|45^WJrF(Brb@Nk$MCWsezMd2Y^*JBTr;>kq=;6SMD^}-O1ZD$2Mg8XvOq5ju5#W*us{%mCZ589L(gLi0 z@AaZ=U8F`D>a}Dvf>R83o&qM4-nSMc{=`J_9)Bri`Qaa=tK8=iXM$loQ zld!-|loFg)rQ(Y7#JsW#)V{VpwXgjI=lZCDhoi$pOm?k#$7hN@`0e}r>#o1dXSd5f z(HML*TXe8s^8_aIGY;eKT;wIFoKZ(`-73ej%dhrda`St9p(4LW;9%yxIoA2+Fia!$ zQ0WDHR-oHeS;!Y%cBL#^ij$28_Hiw9Qm=OyOeBbQYvGcO;TyjGAEh7q?q}S=;$WW4 znEh1BnrARk780vSSREi(t+LoD7v|Y)PMcQ%xIP5Ye1?h0U_ulKXm^x6>(SKEh;*Lt?1#%c%5;DEBeMGaQ|99h{HdX!8*! z$|_zYLcYUz^r^DT77eXgX05njL%ORWuJ*Ro3f`p~K3w+cpa0Ce>h0@%Hml^!S|d}b z=M+p?Yh#xPMJ@?tUKw_gLFL9o@!GJ6GA~14ilZ;Z!NH9NJqKXQZEvSUSe?gE=9Soh zqa-Y>{rhV(u^yM`Tzc7cmZIf_eu+cS0nUfa_qirSfZr~l&?Ukt8v)v;ug$Y>mgk8m zbTRB~R`FU(27M_G@f=f@4#VKA@Dn_;fL~WREdy(>eK(8M?s+NIeWE+6a!zb$GW490 zEF?CGuqYs7p-+NC9$N`I2Rs&rcP*6h$qVdQ8y3L`;M}lO=Ykm8;pkO3HaF?$=uaro z!!N%oq`RA{QjG_id7yj=<&^|whGBQwe0|J;0C2!65yCDJ3w#pX76Fv~k_Ht=P<0@c zI}V;bx5vt`Dqn=(#?YVQh^CG2#(Jd8m&Y6)QJ|{(S#WdtUwZ_XN&) zCLL)yl59M1R0x!;VfhR51xAo*oP%<65GM2Pa$6V{_+*5f0wl%;>pOJ!odPBR90Y+8 zirfMg`bB6Q=!omkbPj=y(m-<@CYEi71Kk`?)#|8kXzb~D^6u~S?s)viJe}$?hX!bcBCn6mF}5~0j1p~5G@Au|k4Crl8g!G8&G%7kTk zBFel1`W24;6bJaJ8g*{L#0XF{j#o}_{JA=NBJ+T}{CJa;VZx{g~2g8bx z2!Vk96h|VXgRz`?%t4q02J|Q#PuJ@F)uyD{wdK)GT~FM3Te7`oD=?HKhpAGp35TA$+0?f2qq4|DKjke%P97UuuAMCcqRiTWUnPN!UCUw3ZHG zTTl-!s$jBJvI?W;OPWnEnXf#%fW-j`MJ^GdU^f3yqfZq~W;soVzQiqHQNVcgbtQDD zngPOWg-IYF%{g|pbN<)54DUF+<51+$|M#{2s%^gk*T-BDecE^?Jr!$D)a=@>^t3`+ zdc``8NrGJ@GDpd08%%&PNn7EQu*fgLmFr*+LNGlrA?G`XY&`l3oC5k%9Q}$ueDr*l zz$6e5Q#t~r*9U&t_T;^vP!s+2n2bovTuFDg97;AFs3&KjOb;z7 z5g5THfS2O+NrHKs-SN3pTg{d;N!EYHi!iyS zCXx;NUspP6dRXzAb&5UUu!@ACY-m#eQ}!-$$PASM2}^guY6Jw643o%!t`x_!jlj{4SUR%lq2EL{J#+HdiqcWH zFMe#to8$~ENck2NilWHu;)qI~HB3CK078jJ!1;wT3S0sNHq?r_jX2j}GXEnGAJ8OLn%aN+m2dWLf9wHGNsKyvG+vp6#1&ju2Rdt` zhqvrt&OmuOud+fHWx**9r6N8Xm;gg*ejCGzkc=fk309GTk7&rb4pZ(qM8SCU6}cEx z&e5-MX!?+kbEYscGD2u}b#c7f%F%w{)kB@X`O=r7N4Gyd8A-q;*02Atd&a~-DK?>USRmvXNFkA={a z(2-J&aiBASNgzPcfgNo+cDJi~_wGM$>wMy_FDF`#ZpI|#sG8LLOgy9XC2DrP9Ix5c zNX2W`#;tiCt4L%QMwn@w8YaNVYgFJ8abcm1g?Q?+2&fE* z#)NB1&#_YDgGnHuBgyf%W{x9G9RrAi2`$slB;Pnn9MtJMM%P$unbSu!5*~%aO%dG>oDb7DXT~*^D_8t42lNC z(nfssu*cpAT^jE>8l%9ACpemFs#+p{`t}ccwmtfQu4X1ZKl+pp|ob{FaMhBS`t$rQ<-g-Yl*&=fql>YUQ?1mCAf4!RCL*V7C>f0 zFaZW&K|8~RMH0>{kl~Pw1BM#(EtqoO%L1X)BcR+TK+%ABnnTZy!LjV}{glSBt)1ib zrh#Pl?x(jk|K~?;O|{p)G|@CU6Orl21Fj|--rSmQuj!-kvK4V#&|?*mO$tV^h=dg( z5$lR1gq?z!3L>Y$-hyeg_c}Kwk4xMFyjF%jMMo-Q1hRE296LKWj<@y2yZ`#YFS<58 zbe9_MJLB=A@yhhz=^EHD$#Pf=2|ZA{utLWe`<3iroU-7SrK=%QBs=-as~pP2)HgQL(*Q!HEGCc~*u3 z2O%lgWu@%W3&Ayiy6yN;J)NBLt;41oCSn#xD0t21A1b=(8=nc}mjufkj2wb7O4gm! z5leH__UL%CT?IfW^9Yaxvzf9d!CNqmR<@P_6GrwDi_-sWn=ll0Ynly z(%AvH0Y%52whT^0b@*%yd3G9#*T!2g<<_M?rDJbf8m}}c=uYY&&|oi476^7a9TLtIFB2c2Cxi?ub zJ_8xQ3EPdmeY>Q5A760EB{a|>Bu`YmhAFU6lMWM;tsdu!t3FZj>7PB|EnQJj;*a z{9GVom!~o}QC#*qGYhZ0m=P5!ZO4x4X{8^NxFOG^!o+N@^58o^^UZ>r?!L_*Ec6%I z8QIOCwei4Y9!G|iiX?RG?NHH|WUZbsX(hAqfnn9svTw$_s7c$vdy%sR4Vsqqgd7H{&@wn3&-4U3}xe z7Tk2t-M;cwrG+-YB^lX4fDsBkW0;1NB{1XBceqPKT;(WnF*u~5mYJ(C5sW!CjT?`& zXRA{<+?4^rNcNr!%h|w`TQ;A?NFqNVxNYh3OV^WRD@ZrKdFX7mvOi;(n8h9rT=~&E z!#8~Gvw?#0VAu-S%(Iy=4E^`4VWO<^7$c-Kpsr6vW4{iMl_BI{CpA#+``HeYK!z@! zsaEhxgM!|a5zi&Cp%9Zvg(+JQmkgA<32DJ94FuONm)v=al&1ZMwN&hk!gtRECMNld zRutU)t)CaZ=Sv^VbGvMXmYf{nSq)AVOs3+92we$|-EAt`<2p**%vimPp$pGumbeg>yi5+ZqPmq?YD{+-ftxK{1&Xqo7C zVH1Oi$YQTJ|N4R(zw!Oxh8r&r%0NIKu1NFERKjGw%w4#fqdIDPH4p*$4hD-jJPvBM z!DPC6MP-{8ZmhSI7dMZ}Ngo&77wHB|qZo$9)^5?#_@3<)6?XdWzq33NJ&90awSf!H}Dx3vWK5W(Kf=>=$xY~&atl}gOmn@>U2l**y;+~ab} z31d=rds7CF>`vhI6B(p+eo~0YT!YDMN4p5D3J{!DS?u($tYl>uUYY4?=uvyyYR!x( zCM%*`wEXJQ4?p-HfeYVrsoyS(K5=;C&vls0^D+Wdoui>&L*sx3w}s%d(ol#?wvZwN zY$Ag!7$eaZkzkjMbEUI;%$VmR0Cl|@9zB@EpQ?<2HA$e;z%Ykk%Kl^cQG`4jqb_S{ zh!$M3QSEC_DeW~!!S$3tjM=;^ue_z;gZF>mzih*@piD#KN4e0<3z&vJV?^jr>!|M4 z(39i{I~bhVJyWbA!74HcM99r;ATWYWB3J~5w9dgnP&AG|A5-wlHC&RGY;5G5EAtViTt(|T z&=S>guuFv`5DHu(T=Gz?&}h1l1waxAZ?vkoe|sFyRVzrU81#)sHvW8qiL#mq*a+w4 zF({(L8moBQMd?J;D>^FHZnOkSeC})toO5GeqT#{_=uL4vRh>q4Sy6n#000u4Nkln4WDg8g`vQ z7%+cfVgOp>z@O@LJX@RAns-0HtM$>Z+&yq$^DhJdTuVk(|O zM3$UHUGoVh9mb32{wC*KMlUVvp!aEL?$hwd>q+cr&SV>Zs24X{qm2Y$KETA7k-hGX z4vwd4HGZ(JrLX&MKY6V4FF&|D)q3n@fTxH0ZMqguwH@CZJ@B{fIwwEEm1PQ(C5u30 zrW2gYFqs9?v)2XF^P7&NV$ba3Xr-l}(A3s$RH4g=ue5kY{}< zAs4DS1QSe4#7C5844A+HmjyU4NLc14^rV2+sIjM9TEkG8=Q&Iw0}?97?oN*1S8M!m zb$w^|3y=J|)%wtc6TQS*e-)s-nG2{Oy(R?2~5 zw!=iAq1A>XAsPiH4!~yxF3e{rbs2t9SAwIi&v3Tg7GuRsB9n8?c?J^$AP7Jt$??Zp z9Xnce-oERvdpe)I>+Ah{HvL>v5~F5SIaLUXrX~8@;>Wf>J8&8vl;V!#+F~>hiNzz zvlAwB9&=|K$M0)&R978r==kHe|Eu#a4}4DPYS?qC$jj3Q$8kNK>1{pSe_->gT-R)x zucTbDdhHS$%A`BnV9LD^<&`Evi^SAN6Q^uXy*8F$z&&nVsT+BbG4 zn+`QGfAM0~R~pn{tVm%r1kFstGofCl${Hc`57aE-C_ii z#nOgj&W4rs)Ru`bdtegCm;~S1rt=q?b*gV^?~gq7ou5RW|Bw4pk>=ev&DLNOh6wHwfyw+UF#{+fAfb+Z+(|Ie&|{7$n>uF-Vao0|iN+Z4Y=h4C zortD7xBm9Uj>qr%V(jRvzt_{L?lVQ=Y;z58o=)~B>fYEqaPY;w%v)HdxQhxhOct#I zAZAU#WWr?n7$cQAUYHmGWp2XSpb>IHBO2^XVPa&&P5Z12Rso2n4R?J)Fy)lpuu_u? zlRzBt46wD03sa_-;Mn3C*Q~nM2?@ywqUt3Sy@nYE!I;PJ@oQ+HQKEr zzjAR(_ShK%*~F}snhcm&&ioex7{(71U<|@7^cthumTan@k$3;uz+{XT1FoFNOqGx3 z3yltw`5gw29W7bK#9?B@K}4t@0A4!5aiFCq(Y@_=&qx0Ft-GVgcRtCvJ}F7&CwcFb zR8O*T|F-^p&%aJ~UuoJ~8de~Qb`fMoG6EBaiII`tT3{mw*Tw-;7A30$tOyV)JY-nR z(Hiw^VaoZ9OD1@%42sH!)p0y94O(%c5x6Js;(tcC#rVGkMDS0m+T9*{G}x+E-<@D zkeM-0)^)1PabyhXo1wF#HS+0T0s%q0F~4SxXph!lQvs9N(2`)pm=hTz%cEZRbmL6f zx)4rw&_{zw76>sF*wL=@-JP7;t9I3QJodFadtZCv5iQOO*VpUsT zNHiYkpuF;mggxW~V`LG4?lE8z7(rwhTueC@Fk`|5qk#$?hJWOgPF|}v9Wa^yH>O}1 ztRf+*m^+0}04DSEtX2ueV}CT51V*Tj0x!4dyt=8ir|X5EJkkE-Jzq#PAKJ_{^{kS4 zold4DsXSNHF{SPJYXb*1?}pWxpK=x!s*=M(I-sb0$c)2ScQ)i3of%A`0F=21m0rWq z9@#k436uGmK!Dpqa7YXZl|#+-qb4{4PQWlA&6m>x?C&9LZAqz}hqfK+c>Jz=dbj=d zM_Mx4f@z4zo}Rr^vZAM=EwN+Uw~MY|iCngNg-k?k!OItfK?0Xy1(h6Ar1?)dc=zZh@W z|1>yP#%hnr7IC^RWQv}Qwq?3oT1eM)B1!OB81igDf0`qf8EUYJ3J2hpfkj@1plvAU z_-qpng3AJ|$rn+dU1r74u+jv;Z6z%5G6d{KP6QB#7VYjy_nbHm&ZlfQg3)B!VFF;> zaxk1z5yliu&;~dpLa(9^&T)-bI0yVzV1b9hD--nW-8x%^bHhM1zwfGXs-(aRx9x^!#^AfK6iPO=YbVKebAD_8-5^@Q-ZS zjB#^8OrR=!#tN90f$+%B*meO z75u;rN4vmb_($?=Hbr9y2Oxk@?q%>;2=#rMk!@wPs&GISfeN31Qa6K~?O2Rv(D)49 zQ8NP5cq;3Z304v4Q#ksS;Y*T?h)1B*MF`oA6nb;TB8?^-Myem11l06sh^H~Eu7Htm zvce}IU>mYVqn?Wc8aNn@GYDxCWjZ%69F)^FJjc*uAZ#}*k4+r<(kcMuE`~fC4NjNL zbul^+gylgIdG?_?i40iaV^|Rq;IkTixYON?=agkKWjq)V5!@ETQuU-b6pf?QHI!sx zJ_!fGDFG`(A{zTOs2Wi2V}>;%8cfzdnh<8lGUUiiz@&+4BB5$JS9HL}a9UHvx$#&F zI}A%?5$7LBrWj*ohJ#IH%x7|*T`)SvZwSVA^z{QA{VAQ3t|_{vjyvV@WXVjx%%gjs ze!9PIe^tvsGSjV|T2X^Pf-y)bveTRSxh`h!RvbsCf(S@tfIrvi_{n}nuRngcF}?Fw zzthyr83(zYsZ8q#xG9-bye)a?g`H_7C2@aoN!seQi_BP#o;y!Bazxl15g$2oK5}$; z?AHvBfR9z)QKA7xD}QbvpGd}DD@S@b{!+)WttJxd*#7(H`<}e>uKwD+PhkqTPaR8U z1SSB`ltf3ee$UQi!~Qz>ik52r@?ZvlLmXO@H=YJM=U~b%F-xi(&o$|Iu}SCkO-;R# z$M5)V@0S04Al1{l4>Ob*X~tjzV61kDG#%{Uv*{_N=LF~8;-a`U&m#y#)|}w_w_w8H z#yn}A<6t+(lhr!**0l9>zV!1yxBdFIPsi%^{7Fxz`ew2@XBMWca5WuGHtc&fc5KI+ zT(*bPzVc#4w1`##um~7jAb3v0#DI<@@O-0=t<4#|b>EglktgrEyLa2852=ZPddz}6 zZLcY4#Ff5po8O$PLAgqHGaIQt*`6p zAO1S>*B{=MXgaugvf{TVLuM09005p*`co&4ZtL0pyXUyYS&(!Ug`>=AwMj%)fgp?s z*O;#`8R5+w?FnF0qmJzj1If<)ue{Oz(~o|(Z{PDj){@b7%mQnaE3*zJQ@E;h#g1-! zNjY(}O|yH86W)d43@6w{V+8!ve$?ECNo0hi%CW1HV@oSXL(Q?a?x%n7NMzHG?p1o* zch7Lsj487gCIEo0CX~*){qd@;n=^@icRH}Bte@;wStN3Zlnq^-2vD;dCLz1Bw>bv9 z*sSpbt+7<+&OdBxf9z|w#SXvnn64zwXot$_lGzQDA-bN5b;pnId@gqQl>?g1liz1A zE{u^?bV)|y3^PZ-T!qQJDF)IUJ3D~wtr@-f;Lal*kA3yN?#(~BH`CvFmG6fN=md`(P5XD|KoHICi${yt*wCkG$~H zCnJCP{x{)a`w5JoRv9AX1B2=3t*r<{V4_vI{-?nxY3@ z*rc=_?@_G2aHpd@oYsvIbcZW;T|J^SNdwmh^OSMQg5%5_~J&Z6DFfnHI)Oypv z-iXd?`*n2f*|fL)u{*y!@a8kW(#OaZIag#(!;}?GOAK_xkG{GocIc%;sw2O+O)3a= zYqIFIz*vAeO0RD^VG^=0MF)=c1N*vEz3up$HLbt>>i0UIdH8GT?&dea_4Ewu@vLP& zz+?#5Gnu~jBhmfOZ{cd%5_6W6b;9cq7?CF%0zBQz!%dJt91#Vm>I3RKBC(#={3>(d^SJ>7CHzytu`S|+Y^)V(pV z^NCG5;OVj!7gwj;cDqF6wP1Mu?+L(U4nHI{&Kr|NC%Ss#eFtBBt?@rU_NiFa)?Z}P zAI~e_Xe>ErU^0bkYHy-u*OqkCfrgA|3%59zmUJZnpVfHunXrrpCPv0$h^{oyngqHV zt4?(M@!LP@diKZPR-=&vI7c8d<(z{F0JyFx=}7b8_~Dl~rF&b&UROowv6RcM6JsHp zvFiX%0Tat^^O590OG4+7-riWpE5CZK_0c;%8?SloDV|PEC>i^Fk#iEJtZ+S}#1i#y zzLY$)c~_dr{zj?1v>|1c+_GV%Bmyu3CPsh?Ad&%E5~?2A_u}5x$M3qY=apZ5SBv-7 zgY)TLl|5_ZT!zUMO^x+7CXesfsr9zTV%~*I8dRS%sS)MdjWo=iaRVk~dukmi&O0Mr zvA&o7`w#7ZdElN@)Bb1A1qb_d@)k^4(baT+s^##`*q*0fR7uEdl1huJqBe`$!iaOA zp`W8e;k+{%R|bx5+u!+%Pkpgx_h0^9i}y6(9P^FFlDA;W70z`n6>E!CZGA4&a=0xa zI72m3MPYlAQHKIV>JBxvKlAYawEgirUrR+=UgNr!ndu_WCZU-wz^oM_NpuIxz3boi zCD)pFzD+rCtf6PiufDIe*X-u{)Ml-ntMdN=GhzB&Av4KY00000NkvXXu0mjfRaq@? literal 0 HcmV?d00001 diff --git a/data/images/dropbox-icon.svg b/data/images/dropbox-icon.svg new file mode 100644 index 0000000000..25ea16033f --- /dev/null +++ b/data/images/dropbox-icon.svg @@ -0,0 +1,1584 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources.qrc b/resources.qrc index c9cc76bcf2..e7d1f07e17 100644 --- a/resources.qrc +++ b/resources.qrc @@ -149,5 +149,6 @@ data/images/ok.svg data/images/tweet.svg data/images/widget-border.png + data/images/dropbox-icon.png diff --git a/src/TomahawkApp.cpp b/src/TomahawkApp.cpp index c5026fad43..7952650048 100644 --- a/src/TomahawkApp.cpp +++ b/src/TomahawkApp.cpp @@ -32,6 +32,7 @@ #include "accounts/AccountManager.h" #include "accounts/spotify/SpotifyAccount.h" #include "accounts/lastfm/LastFmAccount.h" +#include "accounts/dropbox/DropboxAccount.h" #include "database/Database.h" #include "database/DatabaseCollection.h" #include "database/DatabaseCommand_CollectionStats.h" @@ -651,6 +652,9 @@ TomahawkApp::accountManagerReady() m_accountManager.data()->addAccountFactory( spotifyFactory ); m_accountManager.data()->registerAccountFactoryForFilesystem( spotifyFactory ); + Tomahawk::Accounts::DropboxAccountFactory* dropboxFactory = new Tomahawk::Accounts::DropboxAccountFactory; + m_accountManager.data()->addAccountFactory(dropboxFactory); + Tomahawk::Accounts::AccountManager::instance()->loadFromConfig(); } diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 1732d3c8a9..98c2e14f78 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -208,6 +208,9 @@ list(APPEND libSources accounts/spotify/SpotifyPlaylistUpdater.cpp accounts/spotify/SpotifyInfoPlugin.cpp + accounts/dropbox/DropboxAccount.cpp + accounts/dropbox/DropboxConfig.cpp + sip/SipPlugin.cpp sip/SipInfo.cpp sip/PeerInfo.cpp @@ -356,6 +359,7 @@ set( libUI ${libUI} accounts/AccountFactoryWrapper.ui accounts/spotify/SpotifyAccountConfig.ui accounts/lastfm/LastFmConfig.ui + accounts/dropbox/DropboxConfig.ui ) include_directories( diff --git a/src/libtomahawk/accounts/dropbox/DropboxAccount.cpp b/src/libtomahawk/accounts/dropbox/DropboxAccount.cpp new file mode 100644 index 0000000000..21bcd0cd5b --- /dev/null +++ b/src/libtomahawk/accounts/dropbox/DropboxAccount.cpp @@ -0,0 +1,272 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2012, Leo Franchi + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + +#include "DropboxAccount.h" +#include "DropboxConfig.h" + +#include "infosystem/InfoSystem.h" +#include "utils/TomahawkUtilsGui.h" +#include "resolvers/QtScriptResolver.h" +#include "AtticaManager.h" +#include "Pipeline.h" +#include "accounts/AccountManager.h" +#include "Source.h" + +using namespace Tomahawk; +using namespace InfoSystem; +using namespace Accounts; + +DropboxAccountFactory::DropboxAccountFactory() +{ +} + + +Account* +DropboxAccountFactory::createAccount( const QString& accountId ) +{ + return new DropboxAccount( accountId.isEmpty() ? generateId( factoryId() ) : accountId ); +} + + +QPixmap +DropboxAccountFactory::icon() const +{ + return TomahawkUtils::defaultPixmap( TomahawkUtils::DropboxIcon ); +} + + +DropboxAccount::DropboxAccount( const QString& accountId ) + : CustomAtticaAccount( accountId ) +{ + setAccountFriendlyName( "Dropbox" ); + + AtticaManager::instance()->registerCustomAccount( "dropbox", this ); + + connect( AtticaManager::instance(), SIGNAL( resolverInstalled( QString ) ), this, SLOT( resolverInstalled( QString ) ) ); + + const Attica::Content res = AtticaManager::instance()->resolverForId( "dropbox" ); + const AtticaManager::ResolverState state = AtticaManager::instance()->resolverState( res ); + + if ( state == AtticaManager::Installed ) + { + hookupResolver(); + } +} + + +DropboxAccount::~DropboxAccount() +{ + delete m_resolver.data(); +} + + +void +DropboxAccount::authenticate() +{ + if ( !AtticaManager::instance()->resolversLoaded() ) + { + // If we're still waiting to load, wait for the attica resolvers to come down the pipe + connect( AtticaManager::instance(), SIGNAL(resolversLoaded(Attica::Content::List)), this, SLOT( atticaLoaded( Attica::Content::List ) ), Qt::UniqueConnection ); + return; + } + + const Attica::Content res = AtticaManager::instance()->resolverForId( "dropbox" ); + const AtticaManager::ResolverState state = AtticaManager::instance()->resolverState( res ); + + qDebug() << "Dropbox account authenticating..."; + if ( m_resolver.isNull() && state == AtticaManager::Installed ) + { + hookupResolver(); + } + else if ( m_resolver.isNull() ) + { + qDebug() << "Got null resolver but asked to authenticate, so installing i we have one from attica:" << res.isValid() << res.id(); + if ( res.isValid() && !res.id().isEmpty() ) + AtticaManager::instance()->installResolver( res, false ); + } + else + { + m_resolver.data()->start(); + } + + emit connectionStateChanged( connectionState() ); +} + + +void +DropboxAccount::atticaLoaded( Attica::Content::List ) +{ + disconnect( AtticaManager::instance(), SIGNAL( resolversLoaded( Attica::Content::List ) ), this, SLOT( atticaLoaded( Attica::Content::List ) ) ); + authenticate(); +} + + +void +DropboxAccount::deauthenticate() +{ + if ( !m_resolver.isNull() && m_resolver.data()->running() ) + m_resolver.data()->stop(); + + emit connectionStateChanged( connectionState() ); +} + + +AccountConfigWidget* +DropboxAccount::configurationWidget() +{ + if ( m_configWidget.isNull() ) + m_configWidget = QPointer( new DropboxConfig( this ) ); + + return m_configWidget.data(); +} + + +Account::ConnectionState +DropboxAccount::connectionState() const +{ + return ( !m_resolver.isNull() && m_resolver.data()->running() ) ? Account::Connected : Account::Disconnected; +} + + +QPixmap +DropboxAccount::icon() const +{ + return TomahawkUtils::defaultPixmap( TomahawkUtils::DropboxIcon ); +} + +InfoPluginPtr +DropboxAccount::infoPlugin() +{ + //@TODO : Find out what to return +// if ( m_infoPlugin.isNull() ) +// m_infoPlugin = QPointer< LastFmInfoPlugin >( new LastFmInfoPlugin( this ) ); + +// return InfoPluginPtr( m_infoPlugin.data() ); + return NULL; +} + +bool +DropboxAccount::isAuthenticated() const +{ + return !m_resolver.isNull() && m_resolver.data()->running(); +} + + +void +DropboxAccount::saveConfig() +{ +// No data saved from the widget, OAuth data is stored in the account. +// if ( !m_configWidget.isNull() ) +// { +// setUsername( m_configWidget.data()->username() ); +// setPassword( m_configWidget.data()->password() ); +// setScrobble( m_configWidget.data()->scrobble() ); +// } + + sync(); +} + + +QString +DropboxAccount::accessToken() const +{ + return credentials().value( "password" ).toString(); +} + + +void +DropboxAccount::setAccessToken( const QString& accessToken ) +{ + QVariantHash creds = credentials(); + creds[ "accessToken" ] = accessToken; + setCredentials( creds ); +} + +QString +DropboxAccount::accessSecret() const +{ + return credentials().value( "accessSecret" ).toString(); +} + + +void +DropboxAccount::setAccessSecret( const QString& accessSecret ) +{ + QVariantHash creds = credentials(); + creds[ "accessSecret" ] = accessSecret; + setCredentials( creds ); +} + + +QString +DropboxAccount::accountName() const +{ + return credentials().value( "accountName" ).toString(); +} + + +void +DropboxAccount::setAccountName( const QString& accountName ) +{ + QVariantHash creds = credentials(); + creds[ "accountName" ] = accountName; + setCredentials( creds ); +} + + +void +DropboxAccount::resolverInstalled( const QString &resolverId ) +{ + if ( resolverId == "dropbox" ) + { + // We requested this install, so we want to launch it + hookupResolver(); + AccountManager::instance()->enableAccount( this ); + } +} + + +void +DropboxAccount::resolverChanged() +{ + emit connectionStateChanged( connectionState() ); +} + + +void +DropboxAccount::hookupResolver() +{ + // If there is a dropbox resolver from attica installed, create the corresponding ExternalResolver* and hook up to it + const Attica::Content res = AtticaManager::instance()->resolverForId( "dropbox" ); + const AtticaManager::ResolverState state = AtticaManager::instance()->resolverState( res ); + Q_ASSERT( state == AtticaManager::Installed ); + Q_UNUSED( state ); + + const AtticaManager::Resolver data = AtticaManager::instance()->resolverData( res.id() ); + + m_resolver = QPointer< ExternalResolverGui >( qobject_cast< ExternalResolverGui* >( Pipeline::instance()->addScriptResolver( data.scriptPath ) ) ); + m_resolver.data()->setIcon( icon() ); + connect( m_resolver.data(), SIGNAL( changed() ), this, SLOT( resolverChanged() ) ); +} + + +Attica::Content +DropboxAccount::atticaContent() const +{ + return AtticaManager::instance()->resolverForId( "dropbox" ); +} diff --git a/src/libtomahawk/accounts/dropbox/DropboxAccount.h b/src/libtomahawk/accounts/dropbox/DropboxAccount.h new file mode 100644 index 0000000000..979910ea6f --- /dev/null +++ b/src/libtomahawk/accounts/dropbox/DropboxAccount.h @@ -0,0 +1,105 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2012, Leo Franchi + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + +#ifndef DROPBOXACCOUNT_H +#define DROPBOXACCOUNT_H + +#include "accounts/Account.h" +#include "AtticaManager.h" +#include "DllMacro.h" + +#include + +#include +#include + +namespace Tomahawk +{ + class ExternalResolverGui; + +namespace Accounts +{ + +class DropboxConfig; + +class DLLEXPORT DropboxAccountFactory : public AccountFactory +{ + Q_OBJECT +public: + DropboxAccountFactory(); + + virtual Account* createAccount(const QString& accountId = QString()); + virtual QString description() const { return tr( "Search and read the music stored on your Dropbox account." ); } + virtual QString factoryId() const { return "dropboxmaccount"; } + virtual QString prettyName() const { return "Dropbox"; } + virtual AccountTypes types() const { return AccountTypes( ResolverType ); } + virtual bool allowUserCreation() const { return false; } + virtual QPixmap icon() const; + virtual bool isUnique() const { return true; } +}; + +class DLLEXPORT DropboxAccount : public CustomAtticaAccount +{ + Q_OBJECT +public: + explicit DropboxAccount( const QString& accountId ); + ~DropboxAccount(); + + virtual void deauthenticate(); + virtual void authenticate(); + + virtual Tomahawk::InfoSystem::InfoPluginPtr infoPlugin(); + virtual SipPlugin* sipPlugin() { return 0; } + + virtual bool isAuthenticated() const; + + virtual ConnectionState connectionState() const; + virtual QPixmap icon() const; + virtual QWidget* aclWidget() { return 0; } + virtual AccountConfigWidget* configurationWidget(); + virtual void saveConfig(); + + + QString accountName() const; + void setAccountName( const QString& ); + QString accessToken() const; + void setAccessToken( const QString& ); + QString accessSecret() const; + void setAccessSecret( const QString& ); + + Attica::Content atticaContent() const; + +private slots: + void atticaLoaded( Attica::Content::List ); + + void resolverInstalled( const QString& resolverId ); + + void resolverChanged(); +private: + void hookupResolver(); + + QPointer m_resolver; + QPointer m_configWidget; + +}; + +} + +} + +#endif // LASTFMACCOUNT_H diff --git a/src/libtomahawk/accounts/dropbox/DropboxConfig.cpp b/src/libtomahawk/accounts/dropbox/DropboxConfig.cpp new file mode 100644 index 0000000000..bc8e1c7909 --- /dev/null +++ b/src/libtomahawk/accounts/dropbox/DropboxConfig.cpp @@ -0,0 +1,73 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2012, Leo Franchi + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + +#include "DropboxConfig.h" +#include "ui_DropboxConfig.h" + +#include + +#include "DropboxAccount.h" +#include "database/Database.h" +#include "database/DatabaseCommand_LogPlayback.h" +#include +#include +#include "utils/TomahawkUtils.h" +#include "utils/Logger.h" +#include "utils/Closure.h" + +using namespace Tomahawk::Accounts; + + +DropboxConfig::DropboxConfig( DropboxAccount* account ) + : AccountConfigWidget( 0 ) + , m_account( account ) +{ + m_ui = new Ui_DropboxConfig; + m_ui->setupUi( this ); + + m_ui->accountNameLabel->setText(m_account->accountName()); + + connect( m_ui->associateButton, SIGNAL( clicked( bool ) ), SLOT( testLogin() ) ); + +// connect( m_ui->importHistory, SIGNAL( clicked( bool ) ), SLOT( loadHistory() ) ); +// connect( m_ui->syncLovedTracks, SIGNAL( clicked( bool ) ), SLOT( syncLovedTracks() ) ); + +// connect( m_ui->username, SIGNAL( textChanged( QString ) ), SLOT( enableButton() ) ); +// connect( m_ui->password, SIGNAL( textChanged( QString ) ), SLOT( enableButton() ) ); +} + + +QString +DropboxConfig::accountName() const +{ + return m_ui->accountNameLabel->text(); +} + +void +DropboxConfig::setAccountName(const QString &accountName) +{ + m_ui->accountNameLabel->setText(accountName); +} + + +void +DropboxConfig::associateClicked() +{ + +} + diff --git a/src/libtomahawk/accounts/dropbox/DropboxConfig.h b/src/libtomahawk/accounts/dropbox/DropboxConfig.h new file mode 100644 index 0000000000..66a578f1ca --- /dev/null +++ b/src/libtomahawk/accounts/dropbox/DropboxConfig.h @@ -0,0 +1,61 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2012, Leo Franchi + * Copyright 2013, Rémi Benoit + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + +#ifndef DROPBOXCONFIG_H +#define DROPBOXCONFIG_H + +#include "Query.h" +#include "accounts/AccountConfigWidget.h" +#include "database/DatabaseCommand_LoadSocialActions.h" + +#include +#include +#include + +class Ui_DropboxConfig; + +namespace Tomahawk { + +namespace Accounts { + +class DropboxAccount; + +class DropboxConfig : public AccountConfigWidget +{ + Q_OBJECT +public: + explicit DropboxConfig( DropboxAccount* account ); + + QString accountName() const; + void setAccountName( const QString& ); + +private slots: + void associateClicked(); +private: + + DropboxAccount* m_account; + Ui_DropboxConfig* m_ui; + +}; + +} + +} + +#endif // LASTFMCONFIG_H diff --git a/src/libtomahawk/accounts/dropbox/DropboxConfig.ui b/src/libtomahawk/accounts/dropbox/DropboxConfig.ui new file mode 100644 index 0000000000..4f56a308c4 --- /dev/null +++ b/src/libtomahawk/accounts/dropbox/DropboxConfig.ui @@ -0,0 +1,101 @@ + + + DropboxConfig + + + + 0 + 0 + 402 + 373 + + + + Dropbox Account configuration + + + + + 110 + 10 + 211 + 191 + + + + + + + :/data/images/dropbox-icon.png + + + + + + 70 + 230 + 66 + 17 + + + + Account : + + + + + + 70 + 310 + 98 + 27 + + + + Associate + + + false + + + + + false + + + + 260 + 310 + 98 + 27 + + + + Delete + + + false + + + false + + + + + + 320 + 230 + 66 + 17 + + + + Nd + + + + + + + + diff --git a/src/libtomahawk/utils/TomahawkUtils.h b/src/libtomahawk/utils/TomahawkUtils.h index a245952ef1..3546777105 100644 --- a/src/libtomahawk/utils/TomahawkUtils.h +++ b/src/libtomahawk/utils/TomahawkUtils.h @@ -113,6 +113,7 @@ namespace TomahawkUtils DropTopSongs, LastfmIcon, SpotifyIcon, + DropboxIcon, SoundcloudIcon, AccountNone, Starred, diff --git a/src/libtomahawk/utils/TomahawkUtilsGui.cpp b/src/libtomahawk/utils/TomahawkUtilsGui.cpp index 247be38ebb..f61c343861 100644 --- a/src/libtomahawk/utils/TomahawkUtilsGui.cpp +++ b/src/libtomahawk/utils/TomahawkUtilsGui.cpp @@ -704,6 +704,9 @@ defaultPixmap( ImageType type, ImageMode mode, const QSize& size ) case SpotifyIcon: pixmap = ImageRegistry::instance()->pixmap( RESPATH "images/spotify-sourceicon.svg", size ); break; + case DropboxIcon: + pixmap = ImageRegistry::instance()->pixmap( RESPATH "images/dropbox-icon.svg", size ); + break; case SoundcloudIcon: pixmap = ImageRegistry::instance()->pixmap( RESPATH "images/soundcloud.svg", size ); break; From ab825ba636e53d4f1835948b2f0541b2713383a1 Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Sun, 10 Feb 2013 18:43:51 +0100 Subject: [PATCH 03/76] Add all parameters returned along with the OAuth token received in the signals accesToken and temporaryToken. --- src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.cpp | 6 ++++-- src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.h | 4 ++-- src/libtomahawk/thirdparty/kqoauth/kqoauthmanager_p.h | 2 ++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.cpp b/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.cpp index 0e24b43f92..50ae91e211 100644 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.cpp +++ b/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.cpp @@ -92,6 +92,7 @@ bool KQOAuthManagerPrivate::setSuccessfulRequestToken(const QMultiMaptemporaryTokenReceived(this->requestToken, this->requestTokenSecret); + emit q->temporaryTokenReceived(this->requestToken, this->requestTokenSecret, this->results); } if (currentRequestType == KQOAuthRequest::AccessToken) { // Signal that we are ready to use the protected resources. - emit q->accessTokenReceived(this->requestToken, this->requestTokenSecret); + emit q->accessTokenReceived(this->requestToken, this->requestTokenSecret, this->results); } emit q->receivedToken(this->requestToken, this->requestTokenSecret); diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.h index 6778626de3..a99b870f00 100644 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.h +++ b/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.h @@ -171,7 +171,7 @@ class KQOAUTH_EXPORT KQOAuthManager : public QObject // This signal is emited when temporary tokens are returned from the service. // Note that this signal is also emited in case temporary tokens are not available. - void temporaryTokenReceived(QString oauth_token, QString oauth_token_secret); // oauth_token, oauth_token_secret + void temporaryTokenReceived(QString oauth_token, QString oauth_token_secret, QMultiMap results); // oauth_token, oauth_token_secret // This signal is emited when the user has authenticated the application to // communicate with the protected resources. Next we need to exchange the @@ -181,7 +181,7 @@ class KQOAUTH_EXPORT KQOAuthManager : public QObject // This signal is emited when access tokens are received from the service. We are // ready to start communicating with the protected resources. - void accessTokenReceived(QString oauth_token, QString oauth_token_secret); // oauth_token, oauth_token_secret + void accessTokenReceived(QString oauth_token, QString oauth_token_secret, QMultiMap results); // oauth_token, oauth_token_secret // This signal is emited when the authorized request is done. // This ends the kQOAuth interactions. diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager_p.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager_p.h index 56078dfdf9..cd2c0a1e05 100644 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager_p.h +++ b/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager_p.h @@ -59,6 +59,8 @@ class KQOAUTH_EXPORT KQOAuthManagerPrivate { QString consumerKey; QString consumerKeySecret; QString requestVerifier; + QMultiMap results; + QString successHtmlFile; From d9c9a700700647921fee42ff273979d9b73748d8 Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Mon, 11 Feb 2013 10:57:24 +0100 Subject: [PATCH 04/76] Change the dropbox SVG icon to a lighter one. --- data/images/dropbox-icon.svg | 1621 +--------------------------------- 1 file changed, 38 insertions(+), 1583 deletions(-) diff --git a/data/images/dropbox-icon.svg b/data/images/dropbox-icon.svg index 25ea16033f..6f63627d18 100644 --- a/data/images/dropbox-icon.svg +++ b/data/images/dropbox-icon.svg @@ -1,1584 +1,39 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 9122e1eb431af00fb904df64c75b2ee46f9b29f8 Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Mon, 11 Feb 2013 10:58:08 +0100 Subject: [PATCH 05/76] Add the link with the custom dropbox account and the JS resolver. Add a layout to DropboxConfig.ui --- src/TomahawkApp.cpp | 3 +- .../accounts/dropbox/DropboxAccount.cpp | 14 ++- .../accounts/dropbox/DropboxAccount.h | 4 +- .../accounts/dropbox/DropboxConfig.cpp | 2 +- .../accounts/dropbox/DropboxConfig.ui | 116 ++++++++---------- src/libtomahawk/utils/TomahawkUtilsGui.cpp | 2 +- 6 files changed, 74 insertions(+), 67 deletions(-) diff --git a/src/TomahawkApp.cpp b/src/TomahawkApp.cpp index 10810568d5..386c14d124 100644 --- a/src/TomahawkApp.cpp +++ b/src/TomahawkApp.cpp @@ -653,7 +653,8 @@ TomahawkApp::accountManagerReady() m_accountManager.data()->registerAccountFactoryForFilesystem( spotifyFactory ); Tomahawk::Accounts::DropboxAccountFactory* dropboxFactory = new Tomahawk::Accounts::DropboxAccountFactory; - m_accountManager.data()->addAccountFactory(dropboxFactory); + m_accountManager.data()->addAccountFactory(dropboxFactory); + m_accountManager.data()->registerAccountFactoryForFilesystem(dropboxFactory); Tomahawk::Accounts::AccountManager::instance()->loadFromConfig(); } diff --git a/src/libtomahawk/accounts/dropbox/DropboxAccount.cpp b/src/libtomahawk/accounts/dropbox/DropboxAccount.cpp index 21bcd0cd5b..8d864df6b8 100644 --- a/src/libtomahawk/accounts/dropbox/DropboxAccount.cpp +++ b/src/libtomahawk/accounts/dropbox/DropboxAccount.cpp @@ -49,6 +49,18 @@ DropboxAccountFactory::icon() const return TomahawkUtils::defaultPixmap( TomahawkUtils::DropboxIcon ); } +bool +DropboxAccountFactory::acceptsPath(const QString &path) const +{ + return path.endsWith("dropbox.js"); +} + +Account* +DropboxAccountFactory::createFromPath(const QString &) +{ + return new DropboxAccount(generateId(factoryId())); +} + DropboxAccount::DropboxAccount( const QString& accountId ) : CustomAtticaAccount( accountId ) @@ -185,7 +197,7 @@ DropboxAccount::saveConfig() QString DropboxAccount::accessToken() const { - return credentials().value( "password" ).toString(); + return credentials().value( "accessToken" ).toString(); } diff --git a/src/libtomahawk/accounts/dropbox/DropboxAccount.h b/src/libtomahawk/accounts/dropbox/DropboxAccount.h index 979910ea6f..4a64caf9af 100644 --- a/src/libtomahawk/accounts/dropbox/DropboxAccount.h +++ b/src/libtomahawk/accounts/dropbox/DropboxAccount.h @@ -45,12 +45,14 @@ class DLLEXPORT DropboxAccountFactory : public AccountFactory virtual Account* createAccount(const QString& accountId = QString()); virtual QString description() const { return tr( "Search and read the music stored on your Dropbox account." ); } - virtual QString factoryId() const { return "dropboxmaccount"; } + virtual QString factoryId() const { return "dropboxaccount"; } virtual QString prettyName() const { return "Dropbox"; } virtual AccountTypes types() const { return AccountTypes( ResolverType ); } virtual bool allowUserCreation() const { return false; } virtual QPixmap icon() const; virtual bool isUnique() const { return true; } + bool acceptsPath( const QString& ) const; + Account* createFromPath(const QString &); }; class DLLEXPORT DropboxAccount : public CustomAtticaAccount diff --git a/src/libtomahawk/accounts/dropbox/DropboxConfig.cpp b/src/libtomahawk/accounts/dropbox/DropboxConfig.cpp index bc8e1c7909..e96d930802 100644 --- a/src/libtomahawk/accounts/dropbox/DropboxConfig.cpp +++ b/src/libtomahawk/accounts/dropbox/DropboxConfig.cpp @@ -42,7 +42,7 @@ DropboxConfig::DropboxConfig( DropboxAccount* account ) m_ui->accountNameLabel->setText(m_account->accountName()); - connect( m_ui->associateButton, SIGNAL( clicked( bool ) ), SLOT( testLogin() ) ); + connect( m_ui->associateButton, SIGNAL( clicked( bool ) ), SLOT( associateClicked() ) ); // connect( m_ui->importHistory, SIGNAL( clicked( bool ) ), SLOT( loadHistory() ) ); // connect( m_ui->syncLovedTracks, SIGNAL( clicked( bool ) ), SLOT( syncLovedTracks() ) ); diff --git a/src/libtomahawk/accounts/dropbox/DropboxConfig.ui b/src/libtomahawk/accounts/dropbox/DropboxConfig.ui index 4f56a308c4..679d273e9c 100644 --- a/src/libtomahawk/accounts/dropbox/DropboxConfig.ui +++ b/src/libtomahawk/accounts/dropbox/DropboxConfig.ui @@ -6,12 +6,12 @@ 0 0 - 402 - 373 + 410 + 436 - Dropbox Account configuration + Form @@ -29,69 +29,61 @@ :/data/images/dropbox-icon.png - + - 70 - 230 - 66 - 17 + 20 + 220 + 361 + 181 - - Account : - - - - - - 70 - 310 - 98 - 27 - - - - Associate - - - false - - - - - false - - - - 260 - 310 - 98 - 27 - - - - Delete - - - false - - - false - - - - - - 320 - 230 - 66 - 17 - - - - Nd - + + + + + + + false + + + Delete + + + false + + + false + + + + + + + Nd + + + + + + + Associate + + + false + + + + + + + Account : + + + + + + diff --git a/src/libtomahawk/utils/TomahawkUtilsGui.cpp b/src/libtomahawk/utils/TomahawkUtilsGui.cpp index f61c343861..ef19cfc8d3 100644 --- a/src/libtomahawk/utils/TomahawkUtilsGui.cpp +++ b/src/libtomahawk/utils/TomahawkUtilsGui.cpp @@ -705,7 +705,7 @@ defaultPixmap( ImageType type, ImageMode mode, const QSize& size ) pixmap = ImageRegistry::instance()->pixmap( RESPATH "images/spotify-sourceicon.svg", size ); break; case DropboxIcon: - pixmap = ImageRegistry::instance()->pixmap( RESPATH "images/dropbox-icon.svg", size ); + pixmap = ImageRegistry::instance()->pixmap( RESPATH "images/dropbox-icon.png", size ); break; case SoundcloudIcon: pixmap = ImageRegistry::instance()->pixmap( RESPATH "images/soundcloud.svg", size ); From 1831838b6b7309805ff4cd55c108efb7f06fe3c8 Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Thu, 14 Feb 2013 10:31:24 +0100 Subject: [PATCH 06/76] Add the possibility for JS resolvers to register for signals on their config.ui. Remove custom Dropbox account factory from QtResolver. --- .../resolvers/QtScriptResolver.cpp | 63 ++++++++++++++++--- src/libtomahawk/resolvers/QtScriptResolver.h | 5 ++ 2 files changed, 61 insertions(+), 7 deletions(-) diff --git a/src/libtomahawk/resolvers/QtScriptResolver.cpp b/src/libtomahawk/resolvers/QtScriptResolver.cpp index 50a8fc5303..ebb749b672 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.cpp +++ b/src/libtomahawk/resolvers/QtScriptResolver.cpp @@ -45,6 +45,9 @@ #include #include #include +#include +#include +#include #include @@ -349,6 +352,7 @@ QtScriptResolver::QtScriptResolver( const QString& scriptPath ) , m_stopped( true ) , m_error( Tomahawk::ExternalResolver::NoError ) , m_resolverHelper( new QtScriptResolverHelper( scriptPath, this ) ) + , m_signalMapper( new QSignalMapper(this) ) { tLog() << Q_FUNC_INFO << "Loading JS resolver:" << scriptPath; @@ -358,6 +362,8 @@ QtScriptResolver::QtScriptResolver( const QString& scriptPath ) // set the icon, if we launch properly we'll get the icon the resolver reports m_icon = TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultResolver, TomahawkUtils::Original, QSize( 128, 128 ) ); + connect( m_signalMapper, SIGNAL( mapped ( const QString & ) ), this, SLOT( executeJavascript(const QString &) ) ); + if ( !QFile::exists( filePath() ) ) { tLog() << Q_FUNC_INFO << "Failed loading JavaScript resolver:" << scriptPath; @@ -859,9 +865,11 @@ QtScriptResolver::loadDataFromWidgets() QString widgetName = data["widget"].toString(); QWidget* widget= m_configWidget.data()->findChild( widgetName ); - QVariant value = widgetData( widget, data["property"].toString() ); - - saveData[ data["name"].toString() ] = value; + if( data.contains("property") ) + { + QVariant value = widgetData( widget, data["property"].toString() ); + saveData[ data["name"].toString() ] = value; + } } return saveData; @@ -873,7 +881,9 @@ QtScriptResolver::fillDataInWidgets( const QVariantMap& data ) { foreach(const QVariant& dataWidget, m_dataWidgets) { - QString widgetName = dataWidget.toMap()["widget"].toString(); + QVariantMap mapDataWidget = dataWidget.toMap(); + QString widgetName = mapDataWidget["widget"].toString(); + QWidget* widget= m_configWidget.data()->findChild( widgetName ); if( !widget ) { @@ -881,11 +891,45 @@ QtScriptResolver::fillDataInWidgets( const QVariantMap& data ) Q_ASSERT(false); return; } + if( mapDataWidget.contains("property") ) + { + QString propertyName = mapDataWidget["property"].toString(); + QString name = mapDataWidget["name"].toString(); + + setWidgetData( data[ name ], widget, propertyName ); + } + if( mapDataWidget.contains("connections") ) + { + connectUISlots( widget, mapDataWidget["connections"].toList() ); + } + } +} - QString propertyName = dataWidget.toMap()["property"].toString(); - QString name = dataWidget.toMap()["name"].toString(); - setWidgetData( data[ name ], widget, propertyName ); +void QtScriptResolver::connectUISlots( QWidget* widget, const QVariantList &connectionsList ) +{ + foreach( const QVariant& connection, connectionsList ) + { + QVariantMap params = connection.toMap(); + + if( params.contains("signal") && params.contains("javascriptCallback") ) + { + int iSignal = widget->metaObject()->indexOfSignal( params["signal"].toString() + .toLocal8Bit() + .data() + ); + + if( iSignal != -1 ){ + + QMetaMethod signal = widget->metaObject()->method( iSignal ); + QMetaMethod slot = m_signalMapper->metaObject()->method( m_signalMapper + ->metaObject()-> + indexOfSlot("map()") ); + + connect( widget , signal , m_signalMapper, slot ); + m_signalMapper->setMapping( widget, params["javascriptCallback"].toString() ); + } + } } } @@ -945,3 +989,8 @@ QtScriptResolver::resolverCollections() // + data. } +void QtScriptResolver::executeJavascript(const QString &js) +{ + m_engine->mainFrame()->evaluateJavaScript( RESOLVER_LEGACY_CODE + js ); +} + diff --git a/src/libtomahawk/resolvers/QtScriptResolver.h b/src/libtomahawk/resolvers/QtScriptResolver.h index 9ec07c72e8..8092139ec7 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.h +++ b/src/libtomahawk/resolvers/QtScriptResolver.h @@ -31,6 +31,7 @@ #include #include #include +#include #ifdef QCA2_FOUND #include @@ -162,6 +163,8 @@ public slots: virtual void albums( const Tomahawk::collection_ptr& collection, const Tomahawk::artist_ptr& artist ); virtual void tracks( const Tomahawk::collection_ptr& collection, const Tomahawk::album_ptr& album ); + void executeJavascript(const QString& ); + signals: void stopped(); @@ -175,6 +178,7 @@ public slots: void fillDataInWidgets( const QVariantMap& data ); void onCapabilitiesChanged( Capabilities capabilities ); void loadCollections(); + void connectUISlots( QWidget*, const QVariantList & ); // encapsulate javascript calls QVariantMap resolverSettings(); @@ -193,6 +197,7 @@ public slots: QPixmap m_icon; unsigned int m_weight, m_timeout; Capabilities m_capabilities; + QSignalMapper* m_signalMapper; bool m_ready, m_stopped; ExternalResolver::ErrorState m_error; From ac82eac1e73dc59ee72ff14d7867196ea8e245d9 Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Thu, 14 Feb 2013 12:58:52 +0100 Subject: [PATCH 07/76] Remove Dropbox custom account manager from tomahawk. --- src/TomahawkApp.cpp | 5 - src/libtomahawk/CMakeLists.txt | 4 - .../accounts/dropbox/DropboxAccount.cpp | 284 ------------------ .../accounts/dropbox/DropboxAccount.h | 107 ------- .../accounts/dropbox/DropboxConfig.cpp | 73 ----- .../accounts/dropbox/DropboxConfig.h | 61 ---- .../accounts/dropbox/DropboxConfig.ui | 93 ------ 7 files changed, 627 deletions(-) delete mode 100644 src/libtomahawk/accounts/dropbox/DropboxAccount.cpp delete mode 100644 src/libtomahawk/accounts/dropbox/DropboxAccount.h delete mode 100644 src/libtomahawk/accounts/dropbox/DropboxConfig.cpp delete mode 100644 src/libtomahawk/accounts/dropbox/DropboxConfig.h delete mode 100644 src/libtomahawk/accounts/dropbox/DropboxConfig.ui diff --git a/src/TomahawkApp.cpp b/src/TomahawkApp.cpp index 386c14d124..cc0a7d5f54 100644 --- a/src/TomahawkApp.cpp +++ b/src/TomahawkApp.cpp @@ -32,7 +32,6 @@ #include "accounts/AccountManager.h" #include "accounts/spotify/SpotifyAccount.h" #include "accounts/lastfm/LastFmAccount.h" -#include "accounts/dropbox/DropboxAccount.h" #include "database/Database.h" #include "database/DatabaseCollection.h" #include "database/DatabaseCommand_CollectionStats.h" @@ -652,10 +651,6 @@ TomahawkApp::accountManagerReady() m_accountManager.data()->addAccountFactory( spotifyFactory ); m_accountManager.data()->registerAccountFactoryForFilesystem( spotifyFactory ); - Tomahawk::Accounts::DropboxAccountFactory* dropboxFactory = new Tomahawk::Accounts::DropboxAccountFactory; - m_accountManager.data()->addAccountFactory(dropboxFactory); - m_accountManager.data()->registerAccountFactoryForFilesystem(dropboxFactory); - Tomahawk::Accounts::AccountManager::instance()->loadFromConfig(); } diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 2c23e01966..f1e75034df 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -205,9 +205,6 @@ list(APPEND libSources accounts/spotify/SpotifyPlaylistUpdater.cpp accounts/spotify/SpotifyInfoPlugin.cpp - accounts/dropbox/DropboxAccount.cpp - accounts/dropbox/DropboxConfig.cpp - audio/AudioEngine.cpp collection/Collection.cpp @@ -369,7 +366,6 @@ set( libUI ${libUI} accounts/AccountFactoryWrapper.ui accounts/spotify/SpotifyAccountConfig.ui accounts/lastfm/LastFmConfig.ui - accounts/dropbox/DropboxConfig.ui ) include_directories( diff --git a/src/libtomahawk/accounts/dropbox/DropboxAccount.cpp b/src/libtomahawk/accounts/dropbox/DropboxAccount.cpp deleted file mode 100644 index 8d864df6b8..0000000000 --- a/src/libtomahawk/accounts/dropbox/DropboxAccount.cpp +++ /dev/null @@ -1,284 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2012, Leo Franchi - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#include "DropboxAccount.h" -#include "DropboxConfig.h" - -#include "infosystem/InfoSystem.h" -#include "utils/TomahawkUtilsGui.h" -#include "resolvers/QtScriptResolver.h" -#include "AtticaManager.h" -#include "Pipeline.h" -#include "accounts/AccountManager.h" -#include "Source.h" - -using namespace Tomahawk; -using namespace InfoSystem; -using namespace Accounts; - -DropboxAccountFactory::DropboxAccountFactory() -{ -} - - -Account* -DropboxAccountFactory::createAccount( const QString& accountId ) -{ - return new DropboxAccount( accountId.isEmpty() ? generateId( factoryId() ) : accountId ); -} - - -QPixmap -DropboxAccountFactory::icon() const -{ - return TomahawkUtils::defaultPixmap( TomahawkUtils::DropboxIcon ); -} - -bool -DropboxAccountFactory::acceptsPath(const QString &path) const -{ - return path.endsWith("dropbox.js"); -} - -Account* -DropboxAccountFactory::createFromPath(const QString &) -{ - return new DropboxAccount(generateId(factoryId())); -} - - -DropboxAccount::DropboxAccount( const QString& accountId ) - : CustomAtticaAccount( accountId ) -{ - setAccountFriendlyName( "Dropbox" ); - - AtticaManager::instance()->registerCustomAccount( "dropbox", this ); - - connect( AtticaManager::instance(), SIGNAL( resolverInstalled( QString ) ), this, SLOT( resolverInstalled( QString ) ) ); - - const Attica::Content res = AtticaManager::instance()->resolverForId( "dropbox" ); - const AtticaManager::ResolverState state = AtticaManager::instance()->resolverState( res ); - - if ( state == AtticaManager::Installed ) - { - hookupResolver(); - } -} - - -DropboxAccount::~DropboxAccount() -{ - delete m_resolver.data(); -} - - -void -DropboxAccount::authenticate() -{ - if ( !AtticaManager::instance()->resolversLoaded() ) - { - // If we're still waiting to load, wait for the attica resolvers to come down the pipe - connect( AtticaManager::instance(), SIGNAL(resolversLoaded(Attica::Content::List)), this, SLOT( atticaLoaded( Attica::Content::List ) ), Qt::UniqueConnection ); - return; - } - - const Attica::Content res = AtticaManager::instance()->resolverForId( "dropbox" ); - const AtticaManager::ResolverState state = AtticaManager::instance()->resolverState( res ); - - qDebug() << "Dropbox account authenticating..."; - if ( m_resolver.isNull() && state == AtticaManager::Installed ) - { - hookupResolver(); - } - else if ( m_resolver.isNull() ) - { - qDebug() << "Got null resolver but asked to authenticate, so installing i we have one from attica:" << res.isValid() << res.id(); - if ( res.isValid() && !res.id().isEmpty() ) - AtticaManager::instance()->installResolver( res, false ); - } - else - { - m_resolver.data()->start(); - } - - emit connectionStateChanged( connectionState() ); -} - - -void -DropboxAccount::atticaLoaded( Attica::Content::List ) -{ - disconnect( AtticaManager::instance(), SIGNAL( resolversLoaded( Attica::Content::List ) ), this, SLOT( atticaLoaded( Attica::Content::List ) ) ); - authenticate(); -} - - -void -DropboxAccount::deauthenticate() -{ - if ( !m_resolver.isNull() && m_resolver.data()->running() ) - m_resolver.data()->stop(); - - emit connectionStateChanged( connectionState() ); -} - - -AccountConfigWidget* -DropboxAccount::configurationWidget() -{ - if ( m_configWidget.isNull() ) - m_configWidget = QPointer( new DropboxConfig( this ) ); - - return m_configWidget.data(); -} - - -Account::ConnectionState -DropboxAccount::connectionState() const -{ - return ( !m_resolver.isNull() && m_resolver.data()->running() ) ? Account::Connected : Account::Disconnected; -} - - -QPixmap -DropboxAccount::icon() const -{ - return TomahawkUtils::defaultPixmap( TomahawkUtils::DropboxIcon ); -} - -InfoPluginPtr -DropboxAccount::infoPlugin() -{ - //@TODO : Find out what to return -// if ( m_infoPlugin.isNull() ) -// m_infoPlugin = QPointer< LastFmInfoPlugin >( new LastFmInfoPlugin( this ) ); - -// return InfoPluginPtr( m_infoPlugin.data() ); - return NULL; -} - -bool -DropboxAccount::isAuthenticated() const -{ - return !m_resolver.isNull() && m_resolver.data()->running(); -} - - -void -DropboxAccount::saveConfig() -{ -// No data saved from the widget, OAuth data is stored in the account. -// if ( !m_configWidget.isNull() ) -// { -// setUsername( m_configWidget.data()->username() ); -// setPassword( m_configWidget.data()->password() ); -// setScrobble( m_configWidget.data()->scrobble() ); -// } - - sync(); -} - - -QString -DropboxAccount::accessToken() const -{ - return credentials().value( "accessToken" ).toString(); -} - - -void -DropboxAccount::setAccessToken( const QString& accessToken ) -{ - QVariantHash creds = credentials(); - creds[ "accessToken" ] = accessToken; - setCredentials( creds ); -} - -QString -DropboxAccount::accessSecret() const -{ - return credentials().value( "accessSecret" ).toString(); -} - - -void -DropboxAccount::setAccessSecret( const QString& accessSecret ) -{ - QVariantHash creds = credentials(); - creds[ "accessSecret" ] = accessSecret; - setCredentials( creds ); -} - - -QString -DropboxAccount::accountName() const -{ - return credentials().value( "accountName" ).toString(); -} - - -void -DropboxAccount::setAccountName( const QString& accountName ) -{ - QVariantHash creds = credentials(); - creds[ "accountName" ] = accountName; - setCredentials( creds ); -} - - -void -DropboxAccount::resolverInstalled( const QString &resolverId ) -{ - if ( resolverId == "dropbox" ) - { - // We requested this install, so we want to launch it - hookupResolver(); - AccountManager::instance()->enableAccount( this ); - } -} - - -void -DropboxAccount::resolverChanged() -{ - emit connectionStateChanged( connectionState() ); -} - - -void -DropboxAccount::hookupResolver() -{ - // If there is a dropbox resolver from attica installed, create the corresponding ExternalResolver* and hook up to it - const Attica::Content res = AtticaManager::instance()->resolverForId( "dropbox" ); - const AtticaManager::ResolverState state = AtticaManager::instance()->resolverState( res ); - Q_ASSERT( state == AtticaManager::Installed ); - Q_UNUSED( state ); - - const AtticaManager::Resolver data = AtticaManager::instance()->resolverData( res.id() ); - - m_resolver = QPointer< ExternalResolverGui >( qobject_cast< ExternalResolverGui* >( Pipeline::instance()->addScriptResolver( data.scriptPath ) ) ); - m_resolver.data()->setIcon( icon() ); - connect( m_resolver.data(), SIGNAL( changed() ), this, SLOT( resolverChanged() ) ); -} - - -Attica::Content -DropboxAccount::atticaContent() const -{ - return AtticaManager::instance()->resolverForId( "dropbox" ); -} diff --git a/src/libtomahawk/accounts/dropbox/DropboxAccount.h b/src/libtomahawk/accounts/dropbox/DropboxAccount.h deleted file mode 100644 index 4a64caf9af..0000000000 --- a/src/libtomahawk/accounts/dropbox/DropboxAccount.h +++ /dev/null @@ -1,107 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2012, Leo Franchi - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#ifndef DROPBOXACCOUNT_H -#define DROPBOXACCOUNT_H - -#include "accounts/Account.h" -#include "AtticaManager.h" -#include "DllMacro.h" - -#include - -#include -#include - -namespace Tomahawk -{ - class ExternalResolverGui; - -namespace Accounts -{ - -class DropboxConfig; - -class DLLEXPORT DropboxAccountFactory : public AccountFactory -{ - Q_OBJECT -public: - DropboxAccountFactory(); - - virtual Account* createAccount(const QString& accountId = QString()); - virtual QString description() const { return tr( "Search and read the music stored on your Dropbox account." ); } - virtual QString factoryId() const { return "dropboxaccount"; } - virtual QString prettyName() const { return "Dropbox"; } - virtual AccountTypes types() const { return AccountTypes( ResolverType ); } - virtual bool allowUserCreation() const { return false; } - virtual QPixmap icon() const; - virtual bool isUnique() const { return true; } - bool acceptsPath( const QString& ) const; - Account* createFromPath(const QString &); -}; - -class DLLEXPORT DropboxAccount : public CustomAtticaAccount -{ - Q_OBJECT -public: - explicit DropboxAccount( const QString& accountId ); - ~DropboxAccount(); - - virtual void deauthenticate(); - virtual void authenticate(); - - virtual Tomahawk::InfoSystem::InfoPluginPtr infoPlugin(); - virtual SipPlugin* sipPlugin() { return 0; } - - virtual bool isAuthenticated() const; - - virtual ConnectionState connectionState() const; - virtual QPixmap icon() const; - virtual QWidget* aclWidget() { return 0; } - virtual AccountConfigWidget* configurationWidget(); - virtual void saveConfig(); - - - QString accountName() const; - void setAccountName( const QString& ); - QString accessToken() const; - void setAccessToken( const QString& ); - QString accessSecret() const; - void setAccessSecret( const QString& ); - - Attica::Content atticaContent() const; - -private slots: - void atticaLoaded( Attica::Content::List ); - - void resolverInstalled( const QString& resolverId ); - - void resolverChanged(); -private: - void hookupResolver(); - - QPointer m_resolver; - QPointer m_configWidget; - -}; - -} - -} - -#endif // LASTFMACCOUNT_H diff --git a/src/libtomahawk/accounts/dropbox/DropboxConfig.cpp b/src/libtomahawk/accounts/dropbox/DropboxConfig.cpp deleted file mode 100644 index e96d930802..0000000000 --- a/src/libtomahawk/accounts/dropbox/DropboxConfig.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2012, Leo Franchi - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#include "DropboxConfig.h" -#include "ui_DropboxConfig.h" - -#include - -#include "DropboxAccount.h" -#include "database/Database.h" -#include "database/DatabaseCommand_LogPlayback.h" -#include -#include -#include "utils/TomahawkUtils.h" -#include "utils/Logger.h" -#include "utils/Closure.h" - -using namespace Tomahawk::Accounts; - - -DropboxConfig::DropboxConfig( DropboxAccount* account ) - : AccountConfigWidget( 0 ) - , m_account( account ) -{ - m_ui = new Ui_DropboxConfig; - m_ui->setupUi( this ); - - m_ui->accountNameLabel->setText(m_account->accountName()); - - connect( m_ui->associateButton, SIGNAL( clicked( bool ) ), SLOT( associateClicked() ) ); - -// connect( m_ui->importHistory, SIGNAL( clicked( bool ) ), SLOT( loadHistory() ) ); -// connect( m_ui->syncLovedTracks, SIGNAL( clicked( bool ) ), SLOT( syncLovedTracks() ) ); - -// connect( m_ui->username, SIGNAL( textChanged( QString ) ), SLOT( enableButton() ) ); -// connect( m_ui->password, SIGNAL( textChanged( QString ) ), SLOT( enableButton() ) ); -} - - -QString -DropboxConfig::accountName() const -{ - return m_ui->accountNameLabel->text(); -} - -void -DropboxConfig::setAccountName(const QString &accountName) -{ - m_ui->accountNameLabel->setText(accountName); -} - - -void -DropboxConfig::associateClicked() -{ - -} - diff --git a/src/libtomahawk/accounts/dropbox/DropboxConfig.h b/src/libtomahawk/accounts/dropbox/DropboxConfig.h deleted file mode 100644 index 66a578f1ca..0000000000 --- a/src/libtomahawk/accounts/dropbox/DropboxConfig.h +++ /dev/null @@ -1,61 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2012, Leo Franchi - * Copyright 2013, Rémi Benoit - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#ifndef DROPBOXCONFIG_H -#define DROPBOXCONFIG_H - -#include "Query.h" -#include "accounts/AccountConfigWidget.h" -#include "database/DatabaseCommand_LoadSocialActions.h" - -#include -#include -#include - -class Ui_DropboxConfig; - -namespace Tomahawk { - -namespace Accounts { - -class DropboxAccount; - -class DropboxConfig : public AccountConfigWidget -{ - Q_OBJECT -public: - explicit DropboxConfig( DropboxAccount* account ); - - QString accountName() const; - void setAccountName( const QString& ); - -private slots: - void associateClicked(); -private: - - DropboxAccount* m_account; - Ui_DropboxConfig* m_ui; - -}; - -} - -} - -#endif // LASTFMCONFIG_H diff --git a/src/libtomahawk/accounts/dropbox/DropboxConfig.ui b/src/libtomahawk/accounts/dropbox/DropboxConfig.ui deleted file mode 100644 index 679d273e9c..0000000000 --- a/src/libtomahawk/accounts/dropbox/DropboxConfig.ui +++ /dev/null @@ -1,93 +0,0 @@ - - - DropboxConfig - - - - 0 - 0 - 410 - 436 - - - - Form - - - - - 110 - 10 - 211 - 191 - - - - - - - :/data/images/dropbox-icon.png - - - - - - 20 - 220 - 361 - 181 - - - - - - - - - false - - - Delete - - - false - - - false - - - - - - - Nd - - - - - - - Associate - - - false - - - - - - - Account : - - - - - - - - - - - - - From 92b70fbe4fa8238c7c14fd93bda480df646e6049 Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Sun, 17 Feb 2013 19:18:24 +0100 Subject: [PATCH 08/76] Add method to load an external JS file from the resolver folder. --- src/libtomahawk/resolvers/QtScriptResolver.cpp | 8 ++++++++ src/libtomahawk/resolvers/QtScriptResolver.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/src/libtomahawk/resolvers/QtScriptResolver.cpp b/src/libtomahawk/resolvers/QtScriptResolver.cpp index ebb749b672..91cb35b346 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.cpp +++ b/src/libtomahawk/resolvers/QtScriptResolver.cpp @@ -317,6 +317,13 @@ QtScriptResolverHelper::base64Decode( const QByteArray& input ) } +void +QtScriptResolverHelper::addLocalJSFile( const QString &jsFilePath ) +{ + m_resolver->m_engine->mainFrame()->evaluateJavaScript( readRaw(jsFilePath) ); +} + + QSharedPointer< QIODevice > QtScriptResolverHelper::customIODeviceFactory( const Tomahawk::result_ptr& result ) { @@ -927,6 +934,7 @@ void QtScriptResolver::connectUISlots( QWidget* widget, const QVariantList &conn indexOfSlot("map()") ); connect( widget , signal , m_signalMapper, slot ); + //TODO : check if mapping were previously done on widget, if you set the same widget twice the first mapping will be replaced. m_signalMapper->setMapping( widget, params["javascriptCallback"].toString() ); } } diff --git a/src/libtomahawk/resolvers/QtScriptResolver.h b/src/libtomahawk/resolvers/QtScriptResolver.h index 8092139ec7..bcd3f464fb 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.h +++ b/src/libtomahawk/resolvers/QtScriptResolver.h @@ -58,6 +58,8 @@ Q_OBJECT Q_INVOKABLE QByteArray base64Encode( const QByteArray& input ); Q_INVOKABLE QByteArray base64Decode( const QByteArray& input ); + Q_INVOKABLE void addLocalJSFile(const QString& jsFilePath); + QSharedPointer customIODeviceFactory( const Tomahawk::result_ptr& result ); public slots: From 2f3a2e535dfa89200a3597fa41950ca18d8ae84d Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Tue, 19 Feb 2013 16:15:08 +0100 Subject: [PATCH 09/76] Add a method to request a QWebView from a JS resolver. --- src/libtomahawk/resolvers/QtScriptResolver.cpp | 13 +++++++++++++ src/libtomahawk/resolvers/QtScriptResolver.h | 3 +++ 2 files changed, 16 insertions(+) diff --git a/src/libtomahawk/resolvers/QtScriptResolver.cpp b/src/libtomahawk/resolvers/QtScriptResolver.cpp index 91cb35b346..4959ae0a6d 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.cpp +++ b/src/libtomahawk/resolvers/QtScriptResolver.cpp @@ -324,6 +324,19 @@ QtScriptResolverHelper::addLocalJSFile( const QString &jsFilePath ) } +void +QtScriptResolverHelper::requestWebView(const QString &varName, const QString &url) +{ + QWebView *view = new QWebView(); + view->load(QUrl(url)); + + //TODO: move this to JS. + view->setWindowModality(Qt::ApplicationModal); + + m_resolver->m_engine->mainFrame()->addToJavaScriptWindowObject(varName, view); +} + + QSharedPointer< QIODevice > QtScriptResolverHelper::customIODeviceFactory( const Tomahawk::result_ptr& result ) { diff --git a/src/libtomahawk/resolvers/QtScriptResolver.h b/src/libtomahawk/resolvers/QtScriptResolver.h index bcd3f464fb..81d1fe6777 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.h +++ b/src/libtomahawk/resolvers/QtScriptResolver.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #ifdef QCA2_FOUND @@ -60,6 +61,8 @@ Q_OBJECT Q_INVOKABLE void addLocalJSFile(const QString& jsFilePath); + Q_INVOKABLE void requestWebView(const QString& varName, const QString& url); + QSharedPointer customIODeviceFactory( const Tomahawk::result_ptr& result ); public slots: From dc08224de96a00f46c225e08e5f54094cf5c1fc5 Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Wed, 20 Feb 2013 18:29:39 +0100 Subject: [PATCH 10/76] Add Asynch POST request to tomahawk.js --- data/js/tomahawk.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/data/js/tomahawk.js b/data/js/tomahawk.js index 3fa8d7d9b9..e06d80b912 100644 --- a/data/js/tomahawk.js +++ b/data/js/tomahawk.js @@ -249,6 +249,27 @@ Tomahawk.asyncRequest = function(url, callback, extraHeaders) xmlHttpRequest.send(null); }; +Tomahawk.asyncPostRequest = function(url, params, callback, extraHeaders) +{ + var xmlHttpRequest = new XMLHttpRequest(); + xmlHttpRequest.open('POST', url, true); + xmlHttpRequest.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); + if (extraHeaders) { + for(var headerName in extraHeaders) { + xmlHttpRequest.setRequestHeader(headerName, extraHeaders[headerName]); + } + } + xmlHttpRequest.onreadystatechange = function() { + if (xmlHttpRequest.readyState == 4 && xmlHttpRequest.status == 200) { + callback.call(window, xmlHttpRequest); + } else if (xmlHttpRequest.readyState === 4) { + Tomahawk.log("Failed to do POST request: to: " + url); + Tomahawk.log("Status Code was: " + xmlHttpRequest.status); + } + } + xmlHttpRequest.send(params); +}; + /** * * Secure Hash Algorithm (SHA256) From 16b636ec6e86969ed511986c4451a6d2fd33f3ec Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Sun, 24 Feb 2013 16:23:47 +0100 Subject: [PATCH 11/76] Add bind function in tomahawk.js --- data/js/tomahawk.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/data/js/tomahawk.js b/data/js/tomahawk.js index 8ae17d8516..c6285940d1 100644 --- a/data/js/tomahawk.js +++ b/data/js/tomahawk.js @@ -408,6 +408,29 @@ Tomahawk.sha256=function(s){ }; +if (!Function.prototype.bind) { + Function.prototype.bind = function (oThis) { + if (typeof this !== "function") { + // closest thing possible to the ECMAScript 5 internal IsCallable function + throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); + } + + var aArgs = Array.prototype.slice.call(arguments, 1), + fToBind = this, + fNOP = function () {}, + fBound = function () { + return fToBind.apply(this instanceof fNOP && oThis + ? this + : oThis, + aArgs.concat(Array.prototype.slice.call(arguments))); + }; + + fNOP.prototype = this.prototype; + fBound.prototype = new fNOP(); + + return fBound; + }; +} // some aliases From 170a92651740cabdd5fd194030b890d683ea9c77 Mon Sep 17 00:00:00 2001 From: loclamor Date: Tue, 26 Feb 2013 17:11:10 +0100 Subject: [PATCH 12/76] add a cloudstream class to manage cloud stream ; add a Q_INVOKABLE methode in QtScriptResolver to parse ID3Tags from a stream ; modify cmake configuration to use taglib 1.8 at least --- CMakeLists.txt | 2 +- CMakeModules/FindTaglib.cmake | 2 +- src/libtomahawk/CMakeLists.txt | 3 + .../resolvers/QtScriptResolver.cpp | 194 ++++++++++++++++ src/libtomahawk/resolvers/QtScriptResolver.h | 13 ++ src/libtomahawk/utils/cloudstream.cpp | 210 ++++++++++++++++++ src/libtomahawk/utils/cloudstream.h | 88 ++++++++ 7 files changed, 510 insertions(+), 2 deletions(-) create mode 100644 src/libtomahawk/utils/cloudstream.cpp create mode 100644 src/libtomahawk/utils/cloudstream.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d03f3a084e..2f232c2243 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -197,7 +197,7 @@ macro_log_feature(CLucene_FOUND "CLucene" "The open-source, C++ search engine" " macro_optional_find_package(QJSON) macro_log_feature(QJSON_FOUND "QJson" "Qt library that maps JSON data to QVariant objects" "http://qjson.sf.net" TRUE "" "libqjson is used for encoding communication between Tomahawk instances") -macro_optional_find_package(Taglib 1.6.0) +macro_optional_find_package(Taglib 1.8.0) macro_log_feature(TAGLIB_FOUND "TagLib" "Audio Meta-Data Library" "http://developer.kde.org/~wheeler/taglib.html" TRUE "" "taglib is needed for reading meta data from audio files") include( CheckTagLibFileName ) check_taglib_filename( COMPLEX_TAGLIB_FILENAME ) diff --git a/CMakeModules/FindTaglib.cmake b/CMakeModules/FindTaglib.cmake index e0efbef977..17518a350c 100644 --- a/CMakeModules/FindTaglib.cmake +++ b/CMakeModules/FindTaglib.cmake @@ -15,7 +15,7 @@ IF(TAGLIB_FOUND) ELSE() if(NOT TAGLIB_MIN_VERSION) - set(TAGLIB_MIN_VERSION "1.6") + set(TAGLIB_MIN_VERSION "1.8") endif(NOT TAGLIB_MIN_VERSION) if(NOT WIN32) diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 2c23e01966..bc5c4f4c94 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -114,6 +114,7 @@ set( libGuiSources utils/SharedTimeLine.cpp utils/WebResultHintChecker.cpp utils/NetworkReply.cpp + utils/cloudstream.cpp widgets/AnimatedCounterLabel.cpp widgets/BasicHeader.cpp @@ -338,6 +339,8 @@ list(APPEND libSources thirdparty/kqoauth/kqoauthrequest_1.cpp thirdparty/kqoauth/kqoauthrequest_xauth.cpp thirdparty/kqoauth/kqoauthutils.cpp + + ) IF(LIBLASTFM_FOUND) diff --git a/src/libtomahawk/resolvers/QtScriptResolver.cpp b/src/libtomahawk/resolvers/QtScriptResolver.cpp index 50a8fc5303..d160a7ff69 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.cpp +++ b/src/libtomahawk/resolvers/QtScriptResolver.cpp @@ -27,6 +27,11 @@ #include "ScriptCollection.h" #include "SourceList.h" + + +#include "utils/TomahawkUtils.h" +#include "TomahawkSettings.h" + #include "accounts/AccountConfigWidget.h" #include "network/Servent.h" @@ -48,6 +53,37 @@ #include +//--- includes readcloudFile +//#include "taghandlers/tag.h" +# include "utils/cloudstream.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef TAGLIB_HAS_OPUS +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#include +//--- end includes readcloudfile + // FIXME: bloody hack, remove this for 0.3 // this one adds new functionality to old resolvers #define RESOLVER_LEGACY_CODE "var resolver = Tomahawk.resolver.instance ? Tomahawk.resolver.instance : TomahawkResolver;" @@ -60,6 +96,7 @@ QtScriptResolverHelper::QtScriptResolverHelper( const QString& scriptPath, QtScr { m_scriptPath = scriptPath; m_resolver = parent; + network = new QNetworkAccessManager(this); } @@ -314,6 +351,163 @@ QtScriptResolverHelper::base64Decode( const QByteArray& input ) } +void +QtScriptResolverHelper::ReadCloudFile(const QUrl& download_url, + const QString& title, + int size, + const QString& mime_type, + const QString& authorisation_header, + const QString& javascriptCallbackFunction) { + tDebug( LOGINFO ) << "Loading tags from" << title; + + QVariantMap m; + + m["mimetype"] = mime_type.toUtf8(); + m["url"] = download_url; + + CloudStream* stream = new CloudStream( + download_url, title, size, authorisation_header, network); + stream->Precache(); + boost::scoped_ptr tag; + if (mime_type == "audio/mpeg" && title.endsWith(".mp3")) { + tag.reset(new TagLib::MPEG::File( + stream, // Takes ownership. + TagLib::ID3v2::FrameFactory::instance(), + TagLib::AudioProperties::Accurate)); + } else if (mime_type == "audio/mp4" || + (mime_type == "audio/mpeg" && title.endsWith(".m4a"))) { + tag.reset(new TagLib::MP4::File( + stream, + true, + TagLib::AudioProperties::Accurate)); + } else if (mime_type == "application/ogg" || + mime_type == "audio/ogg") { + tag.reset(new TagLib::Ogg::Vorbis::File( + stream, + true, + TagLib::AudioProperties::Accurate)); + } + #ifdef TAGLIB_HAS_OPUS + else if (mime_type == "application/opus" || + mime_type == "audio/opus") { + tag.reset(new TagLib::Ogg::Opus::File( + stream, + true, + TagLib::AudioProperties::Accurate)); + } + #endif + else if (mime_type == "application/x-flac" || + mime_type == "audio/flac") { + tag.reset(new TagLib::FLAC::File( + stream, + TagLib::ID3v2::FrameFactory::instance(), + true, + TagLib::AudioProperties::Accurate)); + } else if (mime_type == "audio/x-ms-wma") { + tag.reset(new TagLib::ASF::File( + stream, + true, + TagLib::AudioProperties::Accurate)); + } else { + tDebug( LOGINFO ) << "Unknown mime type for tagging:" << mime_type; + //return m; + } + + if (stream->num_requests() > 2) { + // Warn if pre-caching failed. + tDebug( LOGINFO ) << "Total requests for file:" << title + << stream->num_requests() + << stream->cached_bytes(); + } + + //construction of the tag's map + + + if (tag->tag() && !tag->tag()->isEmpty()) { + //song->set_title(tag->tag()->title().toCString(true)); + m["track"] = tag->tag()->title().toCString(true); + //song->set_artist(tag->tag()->artist().toCString(true)); + m["artist"] = tag->tag()->artist().toCString(true); + //song->set_album(tag->tag()->album().toCString(true)); + m["album"] = tag->tag()->album().toCString(true); + //song->set_filesize(size); + m["size"] = size; + + if (tag->tag()->track() != 0) { + //song->set_track(tag->tag()->track()); + m["albumpos"] = tag->tag()->track(); + } + if (tag->tag()->year() != 0) { + //song->set_year(tag->tag()->year()); + m["year"] = tag->tag()->year(); + } + + //song->set_type(pb::tagreader::SongMetadata_Type_STREAM); + + if (tag->audioProperties()) { + //song->set_length_nanosec(tag->audioProperties()->length() * kNsecPerSec); + m["duration"] = tag->audioProperties()->length(); + m["bitrate"] = tag->audioProperties()->bitrate(); + } +/* if (tag->tag()->albumArtist()) { + m["albumartist"] = tag->tag()->albumArtist(); + } + if (tag->tag()->composer()) { + m["composer"] = tag->tag()->composer(); + } + if (tag->tag()->discNumber() != 0) { + m["discnumber"] = tag->tag()->discNumber(); + } +*/ + //return m; + } + + //return m; + + QString getUrl = QString( "Tomahawk.resolver.instance.%1( '%2' );" ).arg( javascriptCallbackFunction ) + .arg( m ); + + m_resolver->m_engine->mainFrame()->evaluateJavaScript( getUrl ); + + } + +/* + QVariantMap m; + + m["url"] = url.arg( fi.canonicalFilePath() ); + m["mtime"] = fi.lastModified().toUTC().toTime_t(); +: m["size"] = (unsigned int)fi.size(); +: m["mimetype"] = mimetype; +: m["duration"] = duration; +: m["bitrate"] = bitrate; +: m["artist"] = artist; +: m["album"] = album; +: m["track"] = track; +: m["albumpos"] = tag->track(); +: m["year"] = tag->year(); +: m["albumartist"] = tag->albumArtist(); +: m["composer"] = tag->composer(); +: m["discnumber"] = tag->discNumber(); + m["hash"] = ""; // TODO + + + + tDebug( LOGINFO ) << "###### Scan mimetype ###### :" << m["mimetype"]; + tDebug( LOGINFO ) << "###### Scan duration ###### :" << m["duration"]; + tDebug( LOGINFO ) << "###### Scan bitrate ###### :" << m["bitrate"]; + tDebug( LOGINFO ) << "###### Scan artist ###### :" << m["artist"]; + tDebug( LOGINFO ) << "###### Scan album ###### :" << m["album"]; + tDebug( LOGINFO ) << "###### Scan track ###### :" << m["track"]; + tDebug( LOGINFO ) << "###### Scan albumpos ###### :" << m["albumpos"]; + tDebug( LOGINFO ) << "###### Scan year ###### :" << m["year"]; + tDebug( LOGINFO ) << "###### Scan albumartist ###### :" << m["albumartist"]; + tDebug( LOGINFO ) << "###### Scan composer ###### :" << m["composer"]; + tDebug( LOGINFO ) << "###### Scan discnumber ###### :" << m["discnumber"]; + + return m; +} +*/ + QSharedPointer< QIODevice > QtScriptResolverHelper::customIODeviceFactory( const Tomahawk::result_ptr& result ) { diff --git a/src/libtomahawk/resolvers/QtScriptResolver.h b/src/libtomahawk/resolvers/QtScriptResolver.h index 9ec07c72e8..c106c97ad9 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.h +++ b/src/libtomahawk/resolvers/QtScriptResolver.h @@ -32,6 +32,9 @@ #include #include +#include +#include + #ifdef QCA2_FOUND #include #endif @@ -57,6 +60,15 @@ Q_OBJECT Q_INVOKABLE QByteArray base64Encode( const QByteArray& input ); Q_INVOKABLE QByteArray base64Decode( const QByteArray& input ); + // send ID3Tags of the stream as argument of the callback function + Q_INVOKABLE void + ReadCloudFile(const QUrl& download_url, + const QString& title, + int size, + const QString& mime_type, + const QString& authorisation_header, + const QString &javascriptCallbackFunction); + QSharedPointer customIODeviceFactory( const Tomahawk::result_ptr& result ); public slots: @@ -85,6 +97,7 @@ public slots: #ifdef QCA2_FOUND QCA::Initializer m_qcaInit; #endif + QNetworkAccessManager* network; }; class DLLEXPORT ScriptEngine : public QWebPage diff --git a/src/libtomahawk/utils/cloudstream.cpp b/src/libtomahawk/utils/cloudstream.cpp new file mode 100644 index 0000000000..392c7edb11 --- /dev/null +++ b/src/libtomahawk/utils/cloudstream.cpp @@ -0,0 +1,210 @@ +/* This file is part of Clementine. + Copyright 2012, David Sansome + + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Clementine is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Clementine. If not, see . +*/ + +#include "cloudstream.h" + +#include +#include +#include +#include + +#include +#include + +#include "utils/Logger.h" + + + +namespace { + static const int kTaglibPrefixCacheBytes = 64 * 1024; // Should be enough. + static const int kTaglibSuffixCacheBytes = 8 * 1024; +} + +CloudStream::CloudStream( + const QUrl& url, const QString& filename, const long length, + const QString& auth, QNetworkAccessManager* network) + : url_(url), + filename_(filename), + encoded_filename_(filename_.toUtf8()), + length_(length), + auth_(auth), + cursor_(0), + network_(network), + cache_(length), + num_requests_(0) { +} + +TagLib::FileName CloudStream::name() const { + return encoded_filename_.data(); +} + +bool CloudStream::CheckCache(int start, int end) { + for (int i = start; i <= end; ++i) { + if (!cache_.test(i)) { + return false; + } + } + return true; +} + +void CloudStream::FillCache(int start, TagLib::ByteVector data) { + for (int i = 0; i < data.size(); ++i) { + cache_.set(start + i, data[i]); + } +} + +TagLib::ByteVector CloudStream::GetCached(int start, int end) { + const uint size = end - start + 1; + TagLib::ByteVector ret(size); + for (int i = 0; i < size; ++i) { + ret[i] = cache_.get(start + i); + } + return ret; +} + +void CloudStream::Precache() { + // For reading the tags of an MP3, TagLib tends to request: + // 1. The first 1024 bytes + // 2. Somewhere between the first 2KB and first 60KB + // 3. The last KB or two. + // 4. Somewhere in the first 64KB again + // + // OGG Vorbis may read the last 4KB. + // + // So, if we precache the first 64KB and the last 8KB we should be sorted :-) + // Ideally, we would use bytes=0-655364,-8096 but Google Drive does not seem + // to support multipart byte ranges yet so we have to make do with two + // requests. + + seek(0, TagLib::IOStream::Beginning); + readBlock(kTaglibPrefixCacheBytes); + seek(kTaglibSuffixCacheBytes, TagLib::IOStream::End); + readBlock(kTaglibSuffixCacheBytes); + clear(); +} + +TagLib::ByteVector CloudStream::readBlock(ulong length) { + const uint start = cursor_; + const uint end = qMin(cursor_ + length - 1, length_ - 1); + + if (end < start) { + return TagLib::ByteVector(); + } + + if (CheckCache(start, end)) { + TagLib::ByteVector cached = GetCached(start, end); + cursor_ += cached.size(); + return cached; + } + + QNetworkRequest request = QNetworkRequest(url_); + if (!auth_.isEmpty()) { + request.setRawHeader("Authorization", auth_.toUtf8()); + } + request.setRawHeader( + "Range", QString("bytes=%1-%2").arg(start).arg(end).toUtf8()); + request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, + QNetworkRequest::AlwaysNetwork); + // The Ubuntu One server applies the byte range to the gzipped data, rather + // than the raw data so we must disable compression. + if (url_.host() == "files.one.ubuntu.com") { + request.setRawHeader("Accept-Encoding", "identity"); + } + + QNetworkReply* reply = network_->get(request); + connect(reply, SIGNAL(sslErrors(QList)), SLOT(SSLErrors(QList))); + ++num_requests_; + + QEventLoop loop; + QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); + loop.exec(); + reply->deleteLater(); + + int code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + if (code >= 400) { + tDebug( LOGINFO ) << "Error retrieving url to tag:" << url_; + return TagLib::ByteVector(); + } + + QByteArray data = reply->readAll(); + TagLib::ByteVector bytes(data.data(), data.size()); + cursor_ += data.size(); + + FillCache(start, bytes); + return bytes; +} + +void CloudStream::writeBlock(const TagLib::ByteVector&) { + tDebug( LOGINFO ) << Q_FUNC_INFO << "not implemented"; +} + +void CloudStream::insert(const TagLib::ByteVector&, ulong, ulong) { + tDebug( LOGINFO ) << Q_FUNC_INFO << "not implemented"; +} + +void CloudStream::removeBlock(ulong, ulong) { + tDebug( LOGINFO ) << Q_FUNC_INFO << "not implemented"; +} + +bool CloudStream::readOnly() const { + tDebug( LOGINFO ) << Q_FUNC_INFO; + return true; +} + +bool CloudStream::isOpen() const { + return true; +} + +void CloudStream::seek(long offset, TagLib::IOStream::Position p) { + switch (p) { + case TagLib::IOStream::Beginning: + cursor_ = offset; + break; + + case TagLib::IOStream::Current: + cursor_ = qMin(ulong(cursor_ + offset), length_); + break; + + case TagLib::IOStream::End: + // This should really not have qAbs(), but OGG reading needs it. + cursor_ = qMax(0UL, length_ - qAbs(offset)); + break; + } +} + +void CloudStream::clear() { + cursor_ = 0; +} + +long CloudStream::tell() const { + return cursor_; +} + +long CloudStream::length() { + return length_; +} + +void CloudStream::truncate(long) { + tDebug( LOGINFO ) << Q_FUNC_INFO << "not implemented"; +} + +void CloudStream::SSLErrors(const QList& errors) { + foreach (const QSslError& error, errors) { + tDebug( LOGINFO ) << error.error() << error.errorString(); + tDebug( LOGINFO ) << error.certificate(); + } +} diff --git a/src/libtomahawk/utils/cloudstream.h b/src/libtomahawk/utils/cloudstream.h new file mode 100644 index 0000000000..2c92f5385d --- /dev/null +++ b/src/libtomahawk/utils/cloudstream.h @@ -0,0 +1,88 @@ +/* This file is part of Clementine. + Copyright 2012, David Sansome + + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Clementine is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Clementine. If not, see . +*/ + +//#ifndef GOOGLEDRIVESTREAM_H +//#define GOOGLEDRIVESTREAM_H + +#include +#include +#include +#include + + +#include +#include + +class QNetworkAccessManager; + +class CloudStream : public QObject, public TagLib::IOStream { + Q_OBJECT + public: + CloudStream(const QUrl& url, + const QString& filename, + const long length, + const QString& auth, + QNetworkAccessManager* network); + + //Taglib::IOStream; + virtual TagLib::FileName name() const; + virtual TagLib::ByteVector readBlock(ulong length); + virtual void writeBlock(const TagLib::ByteVector&); + virtual void insert(const TagLib::ByteVector&, ulong, ulong); + virtual void removeBlock(ulong, ulong); + virtual bool readOnly() const; + virtual bool isOpen() const; + virtual void seek(long offset, TagLib::IOStream::Position p); + virtual void clear(); + virtual long tell() const; + virtual long length(); + virtual void truncate(long); + + google::sparsetable::size_type cached_bytes() const { + return cache_.num_nonempty(); + } + + int num_requests() const { + return num_requests_; + } + + // Use educated guess to request the bytes that TagLib will probably want. + void Precache(); + + private: + bool CheckCache(int start, int end); + void FillCache(int start, TagLib::ByteVector data); + TagLib::ByteVector GetCached(int start, int end); + + private slots: + void SSLErrors(const QList& errors); + + private: + const QUrl url_; + const QString filename_; + const QByteArray encoded_filename_; + const ulong length_; + const QString auth_; + + int cursor_; + QNetworkAccessManager* network_; + + google::sparsetable cache_; + int num_requests_; +}; + +//#endif // GOOGLEDRIVESTREAM_H From 1ad944d0aa460b7df7839351fc92273d12e38860 Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Tue, 26 Feb 2013 21:56:55 +0100 Subject: [PATCH 13/76] Change QtScriptResolverHelper::customIODeviceFactory to accept url with HTTP headers. --- .../resolvers/QtScriptResolver.cpp | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/resolvers/QtScriptResolver.cpp b/src/libtomahawk/resolvers/QtScriptResolver.cpp index 570ca660a1..1ddd6c0674 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.cpp +++ b/src/libtomahawk/resolvers/QtScriptResolver.cpp @@ -339,16 +339,36 @@ QtScriptResolverHelper::requestWebView(const QString &varName, const QString &ur QSharedPointer< QIODevice > QtScriptResolverHelper::customIODeviceFactory( const Tomahawk::result_ptr& result ) { + QString urlStr; + QVariantMap request; + QNetworkRequest req; QString getUrl = QString( "Tomahawk.resolver.instance.%1( '%2' );" ).arg( m_urlCallback ) .arg( QString( QUrl( result->url() ).toEncoded() ) ); - QString urlStr = m_resolver->m_engine->mainFrame()->evaluateJavaScript( getUrl ).toString(); + QVariant jsResult = m_resolver->m_engine->mainFrame()->evaluateJavaScript( getUrl ).toString(); + + if(jsResult.type() == QVariant::Map) + { + request = jsResult.toMap(); + + urlStr = request["url"].toString(); + + QVariantMap headers = request["headers"].toMap(); + foreach(const QString& headerName, headers.keys()) + { + req.setRawHeader(headerName.toLocal8Bit(), headers[headerName].toString().toLocal8Bit()); + } + } + else + { + urlStr = jsResult.toString(); + } if ( urlStr.isEmpty() ) return QSharedPointer< QIODevice >(); QUrl url = QUrl::fromEncoded( urlStr.toUtf8() ); - QNetworkRequest req( url ); + req.setUrl( url ); tDebug() << "Creating a QNetowrkReply with url:" << req.url().toString(); QNetworkReply* reply = TomahawkUtils::nam()->get( req ); return QSharedPointer( reply, &QObject::deleteLater ); From 6bf196cb866c334cf66361548343a90b704baa09 Mon Sep 17 00:00:00 2001 From: loclamor Date: Wed, 27 Feb 2013 11:54:45 +0100 Subject: [PATCH 14/76] update of cloudStream reader --- .../resolvers/QtScriptResolver.cpp | 67 ++++++++++++------- src/libtomahawk/resolvers/QtScriptResolver.h | 7 +- src/libtomahawk/utils/cloudstream.cpp | 20 +++--- src/libtomahawk/utils/cloudstream.h | 4 +- 4 files changed, 57 insertions(+), 41 deletions(-) diff --git a/src/libtomahawk/resolvers/QtScriptResolver.cpp b/src/libtomahawk/resolvers/QtScriptResolver.cpp index 1016f6ab22..8c28c49d30 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.cpp +++ b/src/libtomahawk/resolvers/QtScriptResolver.cpp @@ -354,30 +354,47 @@ QtScriptResolverHelper::base64Decode( const QByteArray& input ) void -QtScriptResolverHelper::ReadCloudFile(const QUrl& download_url, - const QString& title, - int size, - const QString& mime_type, - const QString& authorisation_header, - const QString& javascriptCallbackFunction) { - tDebug( LOGINFO ) << "Loading tags from" << title; +QtScriptResolverHelper::ReadCloudFile(const QString& fileName, int size, const QString& mime_type, const QVariant& requestJS, const QString& javascriptCallbackFunction) { + QVariantMap request; + QUrl download_url; + QVariantMap headers; QVariantMap m; + + + + if(requestJS.type() == QVariant::Map) + { + request = requestJS.toMap(); + + download_url = QUrl(request["url"].toString()); + + headers = request["headers"].toMap(); + } + else + { + download_url = QUrl(jsResult.toString();) + } + + tDebug( LOGINFO ) << "ReadCloudFile : Loading tags of " << fileName << " from " << download_url.toString(); + + + m["mimetype"] = mime_type.toUtf8(); m["url"] = download_url; CloudStream* stream = new CloudStream( - download_url, title, size, authorisation_header, network); + download_url, fileName, size, headers, network); stream->Precache(); boost::scoped_ptr tag; - if (mime_type == "audio/mpeg" && title.endsWith(".mp3")) { + if (mime_type == "audio/mpeg") { // && title.endsWith(".mp3")) { tag.reset(new TagLib::MPEG::File( stream, // Takes ownership. TagLib::ID3v2::FrameFactory::instance(), TagLib::AudioProperties::Accurate)); } else if (mime_type == "audio/mp4" || - (mime_type == "audio/mpeg" && title.endsWith(".m4a"))) { + (mime_type == "audio/mpeg")) { // && title.endsWith(".m4a"))) { tag.reset(new TagLib::MP4::File( stream, true, @@ -423,31 +440,21 @@ QtScriptResolverHelper::ReadCloudFile(const QUrl& download_url, } //construction of the tag's map - - if (tag->tag() && !tag->tag()->isEmpty()) { - //song->set_title(tag->tag()->title().toCString(true)); + m["track"] = tag->tag()->title().toCString(true); - //song->set_artist(tag->tag()->artist().toCString(true)); m["artist"] = tag->tag()->artist().toCString(true); - //song->set_album(tag->tag()->album().toCString(true)); m["album"] = tag->tag()->album().toCString(true); - //song->set_filesize(size); m["size"] = size; if (tag->tag()->track() != 0) { - //song->set_track(tag->tag()->track()); m["albumpos"] = tag->tag()->track(); } if (tag->tag()->year() != 0) { - //song->set_year(tag->tag()->year()); m["year"] = tag->tag()->year(); } - //song->set_type(pb::tagreader::SongMetadata_Type_STREAM); - if (tag->audioProperties()) { - //song->set_length_nanosec(tag->audioProperties()->length() * kNsecPerSec); m["duration"] = tag->audioProperties()->length(); m["bitrate"] = tag->audioProperties()->bitrate(); } @@ -461,15 +468,27 @@ QtScriptResolverHelper::ReadCloudFile(const QUrl& download_url, m["discnumber"] = tag->tag()->discNumber(); } */ - //return m; } - //return m; + QString tabTagsJSON = "{"; + //we convert the QVariantMap to JSON to give it as an argument of the callback function + int nbTags = m.count(); + int i = 1; + foreach(const QString& tag, m.keys()) { + tabTagsJSON += "\"" + tag + "\" : \"" + m[tag].toString() + "\""; + if(i != nbTags){ + tabTagsJSON += ", "; + } + i++; + } + tabTagsJSON += "}"; QString getUrl = QString( "Tomahawk.resolver.instance.%1( '%2' );" ).arg( javascriptCallbackFunction ) - .arg( m ); + .arg( tabTagsJSON ); m_resolver->m_engine->mainFrame()->evaluateJavaScript( getUrl ); +} + } diff --git a/src/libtomahawk/resolvers/QtScriptResolver.h b/src/libtomahawk/resolvers/QtScriptResolver.h index df3bf87f16..9f01315e48 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.h +++ b/src/libtomahawk/resolvers/QtScriptResolver.h @@ -67,12 +67,7 @@ Q_OBJECT // send ID3Tags of the stream as argument of the callback function Q_INVOKABLE void - ReadCloudFile(const QUrl& download_url, - const QString& title, - int size, - const QString& mime_type, - const QString& authorisation_header, - const QString &javascriptCallbackFunction); + ReadCloudFile(const QString& fileName, int size, const QString& mime_type, const QVariant& requestJS, const QString& javascriptCallbackFunction); Q_INVOKABLE void addLocalJSFile(const QString& jsFilePath); diff --git a/src/libtomahawk/utils/cloudstream.cpp b/src/libtomahawk/utils/cloudstream.cpp index 392c7edb11..50c967c9bc 100644 --- a/src/libtomahawk/utils/cloudstream.cpp +++ b/src/libtomahawk/utils/cloudstream.cpp @@ -36,12 +36,12 @@ namespace { CloudStream::CloudStream( const QUrl& url, const QString& filename, const long length, - const QString& auth, QNetworkAccessManager* network) + const QVariantMap& headers, QNetworkAccessManager* network) : url_(url), filename_(filename), encoded_filename_(filename_.toUtf8()), length_(length), - auth_(auth), + headers_(headers), cursor_(0), network_(network), cache_(length), @@ -112,9 +112,11 @@ TagLib::ByteVector CloudStream::readBlock(ulong length) { } QNetworkRequest request = QNetworkRequest(url_); - if (!auth_.isEmpty()) { - request.setRawHeader("Authorization", auth_.toUtf8()); + //setings of specials OAuth (1 or 2) headers + foreach(const QString& headerName, headers_.keys()) { + request.setRawHeader(headerName.toLocal8Bit(), headers_[headerName].toString().toLocal8Bit()); } + request.setRawHeader( "Range", QString("bytes=%1-%2").arg(start).arg(end).toUtf8()); request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, @@ -149,19 +151,19 @@ TagLib::ByteVector CloudStream::readBlock(ulong length) { } void CloudStream::writeBlock(const TagLib::ByteVector&) { - tDebug( LOGINFO ) << Q_FUNC_INFO << "not implemented"; + tDebug( LOGINFO ) << "writeBlock not implemented"; } void CloudStream::insert(const TagLib::ByteVector&, ulong, ulong) { - tDebug( LOGINFO ) << Q_FUNC_INFO << "not implemented"; + tDebug( LOGINFO ) << "insert not implemented"; } void CloudStream::removeBlock(ulong, ulong) { - tDebug( LOGINFO ) << Q_FUNC_INFO << "not implemented"; + tDebug( LOGINFO ) << "removeBlock not implemented"; } bool CloudStream::readOnly() const { - tDebug( LOGINFO ) << Q_FUNC_INFO; + tDebug( LOGINFO ) << "readOnly not implemented"; return true; } @@ -199,7 +201,7 @@ long CloudStream::length() { } void CloudStream::truncate(long) { - tDebug( LOGINFO ) << Q_FUNC_INFO << "not implemented"; + tDebug( LOGINFO ) << "not implemented"; } void CloudStream::SSLErrors(const QList& errors) { diff --git a/src/libtomahawk/utils/cloudstream.h b/src/libtomahawk/utils/cloudstream.h index 2c92f5385d..8f0f9d5282 100644 --- a/src/libtomahawk/utils/cloudstream.h +++ b/src/libtomahawk/utils/cloudstream.h @@ -35,7 +35,7 @@ class CloudStream : public QObject, public TagLib::IOStream { CloudStream(const QUrl& url, const QString& filename, const long length, - const QString& auth, + const QVariantMap& headers, QNetworkAccessManager* network); //Taglib::IOStream; @@ -76,7 +76,7 @@ class CloudStream : public QObject, public TagLib::IOStream { const QString filename_; const QByteArray encoded_filename_; const ulong length_; - const QString auth_; + const QVariantMap headers_; int cursor_; QNetworkAccessManager* network_; From b43e45aef3b4c9832503cce0decbdd269e2ebd1d Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Wed, 27 Feb 2013 13:15:41 +0100 Subject: [PATCH 15/76] Fix errors in parsing of ID3 tags (ReadCloudFile) --- .../resolvers/QtScriptResolver.cpp | 19 ++++++++++--------- src/libtomahawk/resolvers/QtScriptResolver.h | 2 +- src/libtomahawk/utils/cloudstream.cpp | 2 ++ 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/libtomahawk/resolvers/QtScriptResolver.cpp b/src/libtomahawk/resolvers/QtScriptResolver.cpp index 8c28c49d30..7cad2f0c4d 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.cpp +++ b/src/libtomahawk/resolvers/QtScriptResolver.cpp @@ -354,12 +354,14 @@ QtScriptResolverHelper::base64Decode( const QByteArray& input ) void -QtScriptResolverHelper::ReadCloudFile(const QString& fileName, int size, const QString& mime_type, const QVariant& requestJS, const QString& javascriptCallbackFunction) { +QtScriptResolverHelper::ReadCloudFile(const QString& fileName, const QString& sizeS, const QString& mime_type, const QVariant& requestJS, const QString& javascriptCallbackFunction) +{ QVariantMap request; QUrl download_url; QVariantMap headers; QVariantMap m; + long size = sizeS.toLong(); @@ -374,7 +376,7 @@ QtScriptResolverHelper::ReadCloudFile(const QString& fileName, int size, const Q } else { - download_url = QUrl(jsResult.toString();) + download_url = QUrl(requestJS.toString()); } tDebug( LOGINFO ) << "ReadCloudFile : Loading tags of " << fileName << " from " << download_url.toString(); @@ -434,7 +436,7 @@ QtScriptResolverHelper::ReadCloudFile(const QString& fileName, int size, const Q if (stream->num_requests() > 2) { // Warn if pre-caching failed. - tDebug( LOGINFO ) << "Total requests for file:" << title + tDebug( LOGINFO ) << "Total requests for file:" << fileName << stream->num_requests() << stream->cached_bytes(); } @@ -445,7 +447,7 @@ QtScriptResolverHelper::ReadCloudFile(const QString& fileName, int size, const Q m["track"] = tag->tag()->title().toCString(true); m["artist"] = tag->tag()->artist().toCString(true); m["album"] = tag->tag()->album().toCString(true); - m["size"] = size; + m["size"] = QString::number(size); if (tag->tag()->track() != 0) { m["albumpos"] = tag->tag()->track(); @@ -475,7 +477,7 @@ QtScriptResolverHelper::ReadCloudFile(const QString& fileName, int size, const Q int nbTags = m.count(); int i = 1; foreach(const QString& tag, m.keys()) { - tabTagsJSON += "\"" + tag + "\" : \"" + m[tag].toString() + "\""; + tabTagsJSON += "'" + tag + "' : '" + m[tag].toString() + "'"; if(i != nbTags){ tabTagsJSON += ", "; } @@ -483,16 +485,15 @@ QtScriptResolverHelper::ReadCloudFile(const QString& fileName, int size, const Q } tabTagsJSON += "}"; - QString getUrl = QString( "Tomahawk.resolver.instance.%1( '%2' );" ).arg( javascriptCallbackFunction ) + tDebug() << "Sending tags to js : " <m_engine->mainFrame()->evaluateJavaScript( getUrl ); } - } - - void QtScriptResolverHelper::addLocalJSFile( const QString &jsFilePath ) { diff --git a/src/libtomahawk/resolvers/QtScriptResolver.h b/src/libtomahawk/resolvers/QtScriptResolver.h index 9f01315e48..0eb6e31c2f 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.h +++ b/src/libtomahawk/resolvers/QtScriptResolver.h @@ -67,7 +67,7 @@ Q_OBJECT // send ID3Tags of the stream as argument of the callback function Q_INVOKABLE void - ReadCloudFile(const QString& fileName, int size, const QString& mime_type, const QVariant& requestJS, const QString& javascriptCallbackFunction); + ReadCloudFile(const QString& fileName, const QString& sizeS, const QString& mime_type, const QVariant& requestJS, const QString& javascriptCallbackFunction); Q_INVOKABLE void addLocalJSFile(const QString& jsFilePath); diff --git a/src/libtomahawk/utils/cloudstream.cpp b/src/libtomahawk/utils/cloudstream.cpp index 50c967c9bc..70c2e5d8d2 100644 --- a/src/libtomahawk/utils/cloudstream.cpp +++ b/src/libtomahawk/utils/cloudstream.cpp @@ -127,6 +127,8 @@ TagLib::ByteVector CloudStream::readBlock(ulong length) { request.setRawHeader("Accept-Encoding", "identity"); } + //tDebug() << request.rawHeader("Authorization"); + QNetworkReply* reply = network_->get(request); connect(reply, SIGNAL(sslErrors(QList)), SLOT(SSLErrors(QList))); ++num_requests_; From d19652854466c11b89c6d0b07dd5c993bf6100ad Mon Sep 17 00:00:00 2001 From: loclamor Date: Wed, 27 Feb 2013 18:07:38 +0100 Subject: [PATCH 16/76] messages de debug sur les headers --- src/libtomahawk/resolvers/QtScriptResolver.cpp | 4 ++-- src/libtomahawk/utils/cloudstream.cpp | 16 ++++++++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/libtomahawk/resolvers/QtScriptResolver.cpp b/src/libtomahawk/resolvers/QtScriptResolver.cpp index 7cad2f0c4d..fb53f01d30 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.cpp +++ b/src/libtomahawk/resolvers/QtScriptResolver.cpp @@ -379,7 +379,7 @@ QtScriptResolverHelper::ReadCloudFile(const QString& fileName, const QString& si download_url = QUrl(requestJS.toString()); } - tDebug( LOGINFO ) << "ReadCloudFile : Loading tags of " << fileName << " from " << download_url.toString(); + tDebug( LOGINFO ) << "#### ReadCloudFile : Loading tags of " << fileName << " from " << download_url.toString(); @@ -485,7 +485,7 @@ QtScriptResolverHelper::ReadCloudFile(const QString& fileName, const QString& si } tabTagsJSON += "}"; - tDebug() << "Sending tags to js : " < #include #include +#include #include #include @@ -46,6 +47,7 @@ CloudStream::CloudStream( network_(network), cache_(length), num_requests_(0) { + tDebug( LOGINFO ) << "#### Cloudstream : CloudStream object created for " << filename_ << " : " << url_.toString(); } TagLib::FileName CloudStream::name() const { @@ -89,18 +91,22 @@ void CloudStream::Precache() { // Ideally, we would use bytes=0-655364,-8096 but Google Drive does not seem // to support multipart byte ranges yet so we have to make do with two // requests. - + tDebug( LOGINFO ) << "#### CloudStream : Precaching from :" << filename_; seek(0, TagLib::IOStream::Beginning); readBlock(kTaglibPrefixCacheBytes); seek(kTaglibSuffixCacheBytes, TagLib::IOStream::End); readBlock(kTaglibSuffixCacheBytes); clear(); + tDebug( LOGINFO ) << "#### CloudStream : Precaching end for :" << filename_; } TagLib::ByteVector CloudStream::readBlock(ulong length) { + const uint start = cursor_; const uint end = qMin(cursor_ + length - 1, length_ - 1); + //tDebug( LOGINFO ) << "#### CloudStream : reading block from " << start << " to " << end << " for " << url_.toString(); + if (end < start) { return TagLib::ByteVector(); } @@ -139,8 +145,13 @@ TagLib::ByteVector CloudStream::readBlock(ulong length) { reply->deleteLater(); int code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + tDebug( LOGINFO ) << "#### Cloudstream : HttpStatusCode : " << code; + foreach (const QNetworkReply::RawHeaderPair& pair, reply->rawHeaderPairs()){ + tDebug( LOGINFO ) << "#### Cloudstream : pair " << pair; + } + if (code >= 400) { - tDebug( LOGINFO ) << "Error retrieving url to tag:" << url_; + tDebug( LOGINFO ) << "#### Cloudstream : Error " << code << " retrieving url to tag for " << filename_; return TagLib::ByteVector(); } @@ -208,6 +219,7 @@ void CloudStream::truncate(long) { void CloudStream::SSLErrors(const QList& errors) { foreach (const QSslError& error, errors) { + tDebug( LOGINFO ) << "#### Cloudstream : Error for " << filename_ << " : "; tDebug( LOGINFO ) << error.error() << error.errorString(); tDebug( LOGINFO ) << error.certificate(); } From d965af22012deac3ea3dbb104ba7d26552d0c640 Mon Sep 17 00:00:00 2001 From: loclamor Date: Thu, 28 Feb 2013 11:01:07 +0100 Subject: [PATCH 17/76] ajout du parametre ID a readCloudFile --- src/libtomahawk/resolvers/QtScriptResolver.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libtomahawk/resolvers/QtScriptResolver.cpp b/src/libtomahawk/resolvers/QtScriptResolver.cpp index fb53f01d30..75f849111f 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.cpp +++ b/src/libtomahawk/resolvers/QtScriptResolver.cpp @@ -354,7 +354,7 @@ QtScriptResolverHelper::base64Decode( const QByteArray& input ) void -QtScriptResolverHelper::ReadCloudFile(const QString& fileName, const QString& sizeS, const QString& mime_type, const QVariant& requestJS, const QString& javascriptCallbackFunction) +QtScriptResolverHelper::ReadCloudFile(const QString& fileName, const QString& fileId, const QString& sizeS, const QString& mime_type, const QVariant& requestJS, const QString& javascriptCallbackFunction) { QVariantMap request; @@ -379,12 +379,12 @@ QtScriptResolverHelper::ReadCloudFile(const QString& fileName, const QString& si download_url = QUrl(requestJS.toString()); } - tDebug( LOGINFO ) << "#### ReadCloudFile : Loading tags of " << fileName << " from " << download_url.toString(); - + tDebug( LOGINFO ) << "#### ReadCloudFile : Loading tags of " << fileName << " from " << download_url.toString() << " which have id " << fileId; + m["fileId"] = fileId; m["mimetype"] = mime_type.toUtf8(); - m["url"] = download_url; + CloudStream* stream = new CloudStream( download_url, fileName, size, headers, network); From 5479175c3d4284cba245eea02f9ca5d6bf67abbd Mon Sep 17 00:00:00 2001 From: loclamor Date: Thu, 28 Feb 2013 11:02:51 +0100 Subject: [PATCH 18/76] ajout du parametre fileID a redCloudFile --- src/libtomahawk/resolvers/QtScriptResolver.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/resolvers/QtScriptResolver.h b/src/libtomahawk/resolvers/QtScriptResolver.h index 0eb6e31c2f..cb119a3720 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.h +++ b/src/libtomahawk/resolvers/QtScriptResolver.h @@ -67,7 +67,7 @@ Q_OBJECT // send ID3Tags of the stream as argument of the callback function Q_INVOKABLE void - ReadCloudFile(const QString& fileName, const QString& sizeS, const QString& mime_type, const QVariant& requestJS, const QString& javascriptCallbackFunction); + ReadCloudFile(const QString& fileName, const QString& fileId, const QString& sizeS, const QString& mime_type, const QVariant& requestJS, const QString& javascriptCallbackFunction); Q_INVOKABLE void addLocalJSFile(const QString& jsFilePath); From 6950daab2a71ec5657d77d209fa439c0f1b66665 Mon Sep 17 00:00:00 2001 From: loclamor Date: Thu, 28 Feb 2013 12:31:25 +0100 Subject: [PATCH 19/76] header authorization replacement --- src/libtomahawk/utils/cloudstream.cpp | 31 ++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/utils/cloudstream.cpp b/src/libtomahawk/utils/cloudstream.cpp index 5b6d817ddc..4d862d91b0 100644 --- a/src/libtomahawk/utils/cloudstream.cpp +++ b/src/libtomahawk/utils/cloudstream.cpp @@ -117,10 +117,34 @@ TagLib::ByteVector CloudStream::readBlock(ulong length) { return cached; } + QString authorizationHeader = headers_["Authorization"].toString(); + QStringList authorizations = authorizationHeader.split(","); + QStringList oneAuthList; + QStringList newAuthorizationHeader; + foreach(const QString& oneAuth, authorizations){ + if(auth.contains("oauth_nonce")){ + oneAuthList = oneAuth.split("="); + QString oauthNonce = oneAuthList[1].replace('"',""); + int newOautNonce = oauthNonce.toInt(0,16); + newOautNonce++; + + oauthNonce = QString::number(newOautNonce,16); + + newAuthorizationHeader.append(authList[0]+"=\""+oauthNonce+"\""); + } + else { + newAuthorizationHeader.append(oneAuth); + } + } + + headers_["Authorization"] = newAuthorizationHeader.join(", "); + QNetworkRequest request = QNetworkRequest(url_); //setings of specials OAuth (1 or 2) headers + foreach(const QString& headerName, headers_.keys()) { request.setRawHeader(headerName.toLocal8Bit(), headers_[headerName].toString().toLocal8Bit()); + } request.setRawHeader( @@ -134,6 +158,10 @@ TagLib::ByteVector CloudStream::readBlock(ulong length) { } //tDebug() << request.rawHeader("Authorization"); + tDebug() << "######## CloudStream : HTTP request : "; + foreach(const QByteArray& header, request.rawHeaderList()){ + tDebug() << "#### CloudStream : header request : " << header << " = " << request.rawHeader(header); + } QNetworkReply* reply = network_->get(request); connect(reply, SIGNAL(sslErrors(QList)), SLOT(SSLErrors(QList))); @@ -145,9 +173,10 @@ TagLib::ByteVector CloudStream::readBlock(ulong length) { reply->deleteLater(); int code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + tDebug() << "######## CloudStream : HTTP reply : "; tDebug( LOGINFO ) << "#### Cloudstream : HttpStatusCode : " << code; foreach (const QNetworkReply::RawHeaderPair& pair, reply->rawHeaderPairs()){ - tDebug( LOGINFO ) << "#### Cloudstream : pair " << pair; + tDebug( LOGINFO ) << "#### Cloudstream : header reply " << pair; } if (code >= 400) { From 013edb605808fc714e32559babf386bb74af2676 Mon Sep 17 00:00:00 2001 From: loclamor Date: Thu, 28 Feb 2013 18:35:35 +0100 Subject: [PATCH 20/76] tentative de modification du oaut_nonce --- src/libtomahawk/utils/cloudstream.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/libtomahawk/utils/cloudstream.cpp b/src/libtomahawk/utils/cloudstream.cpp index 4d862d91b0..b2956233a1 100644 --- a/src/libtomahawk/utils/cloudstream.cpp +++ b/src/libtomahawk/utils/cloudstream.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -122,28 +123,36 @@ TagLib::ByteVector CloudStream::readBlock(ulong length) { QStringList oneAuthList; QStringList newAuthorizationHeader; foreach(const QString& oneAuth, authorizations){ - if(auth.contains("oauth_nonce")){ + if(oneAuth.contains("oauth_nonce")){ oneAuthList = oneAuth.split("="); + tDebug() << "######## CloudStream : oauth_nonce : " << oneAuthList[1]; QString oauthNonce = oneAuthList[1].replace('"',""); + + tDebug() << "######## CloudStream : oauth_nonce : " << oauthNonce; //ok + int newOautNonce = oauthNonce.toInt(0,16); + + tDebug() << "######## CloudStream : oauth_nonce : " << newOautNonce; // =0 !!! newOautNonce++; + tDebug() << "######## CloudStream : NEW oauth_nonce : " << newOautNonce; - oauthNonce = QString::number(newOautNonce,16); + oauthNonce = QString::number(newOautNonce,16).toUpper(); - newAuthorizationHeader.append(authList[0]+"=\""+oauthNonce+"\""); + newAuthorizationHeader.append(oneAuthList[0]+"=\""+oauthNonce+"\""); } else { newAuthorizationHeader.append(oneAuth); } } - headers_["Authorization"] = newAuthorizationHeader.join(", "); + QMap newHeaders = headers_; + newHeaders.insert("Authorization", QVariant(newAuthorizationHeader.join(", "))); QNetworkRequest request = QNetworkRequest(url_); //setings of specials OAuth (1 or 2) headers - foreach(const QString& headerName, headers_.keys()) { - request.setRawHeader(headerName.toLocal8Bit(), headers_[headerName].toString().toLocal8Bit()); + foreach(const QString& headerName, newHeaders.keys()) { + request.setRawHeader(headerName.toLocal8Bit(), newHeaders[headerName].toString().toLocal8Bit()); } From c8522b73286293d921b536f1c6308058c07e9d1d Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Thu, 28 Feb 2013 22:16:02 +0100 Subject: [PATCH 21/76] Add synchronous post request to tomahawk.js --- data/js/tomahawk.js | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/data/js/tomahawk.js b/data/js/tomahawk.js index c6285940d1..2dd8357e78 100644 --- a/data/js/tomahawk.js +++ b/data/js/tomahawk.js @@ -233,6 +233,33 @@ Tomahawk.syncRequest = function(url) } }; +Tomahawk.syncPostRequest = function(url, params, extraHeaders) +{ + var xmlHttpRequest = new XMLHttpRequest(); + xmlHttpRequest.open('POST', url, false); + + xmlHttpRequest.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); + xmlHttpRequest.setRequestHeader("Content-length", params.length); + xmlHttpRequest.setRequestHeader("Connection", "close"); + + if (extraHeaders) { + for(var headerName in extraHeaders) { + xmlHttpRequest.setRequestHeader(headerName, extraHeaders[headerName]); + } + } + + xmlHttpRequest.send(params); + + if (xmlHttpRequest.readyState == 4 && xmlHttpRequest.status == 200) { + return xmlHttpRequest; + } else if (xmlHttpRequest.readyState === 4) { + Tomahawk.log("Failed to do POST request: to: " + url); + Tomahawk.log("Status Code was: " + xmlHttpRequest.status); + } + + +}; + Tomahawk.asyncRequest = function(url, callback, extraHeaders) { var xmlHttpRequest = new XMLHttpRequest(); @@ -257,7 +284,11 @@ Tomahawk.asyncPostRequest = function(url, params, callback, extraHeaders) { var xmlHttpRequest = new XMLHttpRequest(); xmlHttpRequest.open('POST', url, true); + xmlHttpRequest.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); + xmlHttpRequest.setRequestHeader("Content-length", params.length); + xmlHttpRequest.setRequestHeader("Connection", "close"); + if (extraHeaders) { for(var headerName in extraHeaders) { xmlHttpRequest.setRequestHeader(headerName, extraHeaders[headerName]); From 78351e0cee0202b97d87fcaa73f666408077e1f5 Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Mon, 4 Mar 2013 15:48:28 +0100 Subject: [PATCH 22/76] QwebInspector for Javascript resolvers. --- src/libtomahawk/resolvers/QtScriptResolver.cpp | 9 +++++++++ src/libtomahawk/resolvers/QtScriptResolver.h | 1 + 2 files changed, 10 insertions(+) diff --git a/src/libtomahawk/resolvers/QtScriptResolver.cpp b/src/libtomahawk/resolvers/QtScriptResolver.cpp index 7cad2f0c4d..b38776f114 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.cpp +++ b/src/libtomahawk/resolvers/QtScriptResolver.cpp @@ -52,6 +52,7 @@ #include #include #include +#include #include @@ -513,6 +514,14 @@ QtScriptResolverHelper::requestWebView(const QString &varName, const QString &ur m_resolver->m_engine->mainFrame()->addToJavaScriptWindowObject(varName, view); } +void +QtScriptResolverHelper::showWebInspector() +{ + QWebInspector *inspector = new QWebInspector; + inspector->setPage(m_resolver->m_engine); + inspector->show(); +} + QSharedPointer< QIODevice > QtScriptResolverHelper::customIODeviceFactory( const Tomahawk::result_ptr& result ) diff --git a/src/libtomahawk/resolvers/QtScriptResolver.h b/src/libtomahawk/resolvers/QtScriptResolver.h index 0eb6e31c2f..de0d4e1196 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.h +++ b/src/libtomahawk/resolvers/QtScriptResolver.h @@ -73,6 +73,7 @@ Q_OBJECT Q_INVOKABLE void requestWebView(const QString& varName, const QString& url); + Q_INVOKABLE void showWebInspector(); QSharedPointer customIODeviceFactory( const Tomahawk::result_ptr& result ); From 72fb3846b1dd9d817ef726bd690004b6933124e5 Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Wed, 6 Mar 2013 15:41:16 +0100 Subject: [PATCH 23/76] Extra headers and error message for Tomahawk.synchrequest --- data/js/tomahawk.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/data/js/tomahawk.js b/data/js/tomahawk.js index 2dd8357e78..951c461128 100644 --- a/data/js/tomahawk.js +++ b/data/js/tomahawk.js @@ -223,13 +223,23 @@ Tomahawk.valueForSubNode = function(node, tag) }; -Tomahawk.syncRequest = function(url) +Tomahawk.syncRequest = function(url, extraHeaders) { var xmlHttpRequest = new XMLHttpRequest(); xmlHttpRequest.open('GET', url, false); + + if (extraHeaders) { + for(var headerName in extraHeaders) { + xmlHttpRequest.setRequestHeader(headerName, extraHeaders[headerName]); + } + } + xmlHttpRequest.send(null); if (xmlHttpRequest.status == 200){ return xmlHttpRequest.responseText; + }else if (xmlHttpRequest.readyState === 4) { + Tomahawk.log("Failed to do Get request: to: " + url); + Tomahawk.log("Status Code was: " + xmlHttpRequest.status); } }; From 0ff9909dd22dd66761c03657fb9d2506e32ff1d0 Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Wed, 6 Mar 2013 16:30:55 +0100 Subject: [PATCH 24/76] Change error test for duration of a track --- src/AudioControls.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/AudioControls.cpp b/src/AudioControls.cpp index 3f936616b4..4e39f54468 100644 --- a/src/AudioControls.cpp +++ b/src/AudioControls.cpp @@ -230,7 +230,8 @@ AudioControls::onPlaybackStarted( const Tomahawk::result_ptr& result ) qint64 duration = AudioEngine::instance()->currentTrackTotalTime(); - if ( duration == -1 ) + //TODO : check if result.data()->duration() is always valid + if ( duration <= 0 ) duration = result.data()->duration() * 1000; ui->seekSlider->setRange( 0, duration ); From b41520cb2b111c82145cefe905d6e9fe7b9e3bc4 Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Fri, 22 Mar 2013 08:33:48 +0100 Subject: [PATCH 25/76] Remove thirdparty KQoauth, not used anymore. --- src/libtomahawk/CMakeLists.txt | 8 - .../thirdparty/kqoauth/LGPL_EXCEPTION.txt | 22 - .../thirdparty/kqoauth/LICENSE.LGPL | 505 ------------ .../thirdparty/kqoauth/kqoauth2request.cpp | 61 -- .../thirdparty/kqoauth/kqoauth2request.h | 50 -- .../thirdparty/kqoauth/kqoauth2request_p.h | 14 - .../kqoauth/kqoauthauthreplyserver.cpp | 140 ---- .../kqoauth/kqoauthauthreplyserver.h | 52 -- .../kqoauth/kqoauthauthreplyserver_p.h | 53 -- .../thirdparty/kqoauth/kqoauthglobals.h | 52 -- .../thirdparty/kqoauth/kqoauthmanager.cpp | 729 ------------------ .../thirdparty/kqoauth/kqoauthmanager.h | 205 ----- .../thirdparty/kqoauth/kqoauthmanager_p.h | 80 -- .../thirdparty/kqoauth/kqoauthrequest.cpp | 625 --------------- .../thirdparty/kqoauth/kqoauthrequest.h | 157 ---- .../thirdparty/kqoauth/kqoauthrequest_1.cpp | 5 - .../thirdparty/kqoauth/kqoauthrequest_1.h | 12 - .../thirdparty/kqoauth/kqoauthrequest_p.h | 98 --- .../kqoauth/kqoauthrequest_xauth.cpp | 95 --- .../thirdparty/kqoauth/kqoauthrequest_xauth.h | 53 -- .../kqoauth/kqoauthrequest_xauth_p.h | 14 - .../thirdparty/kqoauth/kqoauthutils.cpp | 83 -- .../thirdparty/kqoauth/kqoauthutils.h | 37 - 23 files changed, 3150 deletions(-) delete mode 100644 src/libtomahawk/thirdparty/kqoauth/LGPL_EXCEPTION.txt delete mode 100644 src/libtomahawk/thirdparty/kqoauth/LICENSE.LGPL delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauth2request.cpp delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauth2request.h delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauth2request_p.h delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver.cpp delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver.h delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver_p.h delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthglobals.h delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.cpp delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.h delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthmanager_p.h delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthrequest.cpp delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthrequest.h delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_1.cpp delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_1.h delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_p.h delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth.cpp delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth.h delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth_p.h delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthutils.cpp delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthutils.h diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 89d760dcc7..4bf5dbf733 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -332,14 +332,6 @@ list(APPEND libSources thirdparty/kdsingleapplicationguard/kdtoolsglobal.cpp thirdparty/kdsingleapplicationguard/kdlockedsharedmemorypointer.cpp - thirdparty/kqoauth/kqoauth2request.cpp - thirdparty/kqoauth/kqoauthauthreplyserver.cpp - thirdparty/kqoauth/kqoauthmanager.cpp - thirdparty/kqoauth/kqoauthrequest.cpp - thirdparty/kqoauth/kqoauthrequest_1.cpp - thirdparty/kqoauth/kqoauthrequest_xauth.cpp - thirdparty/kqoauth/kqoauthutils.cpp - ) diff --git a/src/libtomahawk/thirdparty/kqoauth/LGPL_EXCEPTION.txt b/src/libtomahawk/thirdparty/kqoauth/LGPL_EXCEPTION.txt deleted file mode 100644 index 8f73eca773..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/LGPL_EXCEPTION.txt +++ /dev/null @@ -1,22 +0,0 @@ -Nokia Qt LGPL Exception version 1.1 - -As an additional permission to the GNU Lesser General Public License version -2.1, the object code form of a "work that uses the Library" may incorporate -material from a header file that is part of the Library. You may distribute -such object code under terms of your choice, provided that: - (i) the header files of the Library have not been modified; and - (ii) the incorporated material is limited to numerical parameters, data - structure layouts, accessors, macros, inline functions and - templates; and - (iii) you comply with the terms of Section 6 of the GNU Lesser General - Public License version 2.1. - -Moreover, you may apply this exception to a modified version of the Library, -provided that such modification does not involve copying material from the -Library into the modified Library's header files unless such material is -limited to (i) numerical parameters; (ii) data structure layouts; -(iii) accessors; and (iv) small macros, templates and inline functions of -five lines or less in length. - -Furthermore, you are not required to apply this additional permission to a -modified version of the Library. diff --git a/src/libtomahawk/thirdparty/kqoauth/LICENSE.LGPL b/src/libtomahawk/thirdparty/kqoauth/LICENSE.LGPL deleted file mode 100644 index 184ea478b2..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/LICENSE.LGPL +++ /dev/null @@ -1,505 +0,0 @@ - - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauth2request.cpp b/src/libtomahawk/thirdparty/kqoauth/kqoauth2request.cpp deleted file mode 100644 index 28ece6973c..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauth2request.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * This file: Kyle Fowler - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see - */ -#include - -#include "kqoauth2request_p.h" -#include "kqoauth2request.h" - -/** - * Private d_ptr implementations. - */ -KQOAuth2Request_Private::KQOAuth2Request_Private() -{ - -} - -KQOAuth2Request_Private::~KQOAuth2Request_Private() -{ -} - -/** - * Public implementations. - */ -KQOAuth2Request::KQOAuth2Request(QObject *parent) : - KQOAuthRequest(parent), - d_ptr(new KQOAuth2Request_Private) -{ -} - -bool KQOAuth2Request::isValid() const { - // Access token must always be retrieved using the POST HTTP method. - // And then check the validity of the XAuth request. - // Provided by the base class as a protected method for us. - return validateOauth2Request(); -} - -void KQOAuth2Request::initRequest(KQOAuthRequest::RequestType type, const QUrl &requestEndpoint) { - KQOAuthRequest::initRequest(type,requestEndpoint); - setRequestOAuthMethod(KQOAuthRequest::OAUTH2); -} diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauth2request.h b/src/libtomahawk/thirdparty/kqoauth/kqoauth2request.h deleted file mode 100644 index 021d159199..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauth2request.h +++ /dev/null @@ -1,50 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * This file: Kyle Fowler - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see . - */ -#ifndef KQOAUTH2REQUEST_H -#define KQOAUTH2REQUEST_H - -#include "kqoauthrequest.h" -#include "kqoauthrequest_1.h" - -class KQOAuth2Request_Private; -class KQOAUTH_EXPORT KQOAuth2Request : public KQOAuthRequest -{ - Q_OBJECT -public: - KQOAuth2Request(QObject *parent = 0); - - /** - * These methods can be overridden in child classes which are different types of - * OAuth requests. - */ - // Validate the request of this type. - bool isValid() const; - void initRequest(KQOAuthRequest::RequestType type, const QUrl &requestEndpoint); - -private: - KQOAuth2Request_Private * const d_ptr; -}; - -#endif // KQOAUTHREQUEST_XAUTH_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauth2request_p.h b/src/libtomahawk/thirdparty/kqoauth/kqoauth2request_p.h deleted file mode 100644 index 2a0dcd3571..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauth2request_p.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef KQOAUTH2REQUEST_P_H -#define KQOAUTH2REQUEST_P_H - -#include "kqoauthglobals.h" - -class KQOAuthRequest; -class KQOAUTH_EXPORT KQOAuth2Request_Private -{ -public: - KQOAuth2Request_Private(); - ~KQOAuth2Request_Private(); -}; - -#endif // KQOAUTHREQUEST_XAUTH_P_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver.cpp b/src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver.cpp deleted file mode 100644 index 30f25de61d..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see - */ -#include -#include -#include -#include -#include -#include - -#include "kqoauthauthreplyserver.h" -#include "kqoauthauthreplyserver_p.h" - -KQOAuthAuthReplyServerPrivate::KQOAuthAuthReplyServerPrivate(KQOAuthAuthReplyServer *parent): - q_ptr(parent) -{ - -} - -KQOAuthAuthReplyServerPrivate::~KQOAuthAuthReplyServerPrivate() -{ - -} - -void KQOAuthAuthReplyServerPrivate::onIncomingConnection() { - Q_Q(KQOAuthAuthReplyServer); - qDebug() << "Incoming Connection"; - socket = q->nextPendingConnection(); - connect(socket, SIGNAL(readyRead()), - this, SLOT(onBytesReady()), Qt::UniqueConnection); -} - -void KQOAuthAuthReplyServerPrivate::onBytesReady() { - Q_Q(KQOAuthAuthReplyServer); - qDebug() << "Socket peer host address: " << socket->peerAddress(); - QByteArray reply; - QByteArray content; - - QByteArray data = socket->readAll(); - qDebug()<< "Query Data: " << data; - QMultiMap queryParams = parseQueryParams(&data); - if(queryParams.size() == 0 && !handlingRedirect) { //assume theres a hash and do the redirect hack - handlingRedirect = true; - content.append("

Account authorized, go ahead back to the tumblr app and start your experience!

"); - } else { - handlingRedirect = false; - QFile file("app/native/assets/" + localFile); - QString fileData; - if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { - qDebug() << "file worked"; - QTextStream in(&file); - while (!in.atEnd()) { - fileData += in.readLine(); - } - file.close(); - } - if(fileData.isEmpty()) { - content.append("

Account linked, go ahead back to the app and check the status!

"); - } else { - content.append(fileData); - } - } - - reply.append("HTTP/1.0 200 OK \r\n"); - reply.append("Content-Type: text/html; charset=\"utf-8\"\r\n"); - reply.append(QString("Content-Length: %1\r\n").arg(content.size())); - reply.append("\r\n"); - reply.append(content); - socket->write(reply); - - if(!handlingRedirect) { - socket->disconnectFromHost(); - q->close(); - emit q->verificationReceived(queryParams); - } -} - -QMultiMap KQOAuthAuthReplyServerPrivate::parseQueryParams(QByteArray *data) { - QString splitGetLine = QString(*data).split("\r\n").first(); // Retrieve the first line with query params. - splitGetLine.remove("GET "); // Clean the line from GET - splitGetLine.remove("HTTP/1.1"); // From HTTP - splitGetLine.remove("\r\n"); // And from rest. - splitGetLine.prepend("http://localhost"); // Now, make it a URL - - QUrl getTokenUrl(splitGetLine); - QList< QPair > tokens = getTokenUrl.queryItems(); // Ask QUrl to do our work. - - QMultiMap queryParams; - QPair tokenPair; - foreach (tokenPair, tokens) { - queryParams.insert(tokenPair.first.trimmed(), tokenPair.second.trimmed()); - } - - return queryParams; -} - - - -KQOAuthAuthReplyServer::KQOAuthAuthReplyServer(QObject *parent) : - QTcpServer(parent), - d_ptr( new KQOAuthAuthReplyServerPrivate(this) ) -{ - Q_D(KQOAuthAuthReplyServer); - - connect(this, SIGNAL(newConnection()), - d, SLOT(onIncomingConnection())); -} - -KQOAuthAuthReplyServer::~KQOAuthAuthReplyServer() -{ - delete d_ptr; -} - - -void KQOAuthAuthReplyServer::setSuccessHtmlFile(QString filePath) { - Q_D(KQOAuthAuthReplyServer); - d->localFile = filePath; -} - - diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver.h deleted file mode 100644 index 82f6d99d24..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver.h +++ /dev/null @@ -1,52 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see - */ -#ifndef KQOAUTHAUTHREPLYSERVER_H -#define KQOAUTHAUTHREPLYSERVER_H - -#include - -#include "kqoauthglobals.h" - -class KQOAuthAuthReplyServerPrivate; -class KQOAUTH_EXPORT KQOAuthAuthReplyServer : public QTcpServer -{ - Q_OBJECT -public: - explicit KQOAuthAuthReplyServer(QObject *parent); - ~KQOAuthAuthReplyServer(); - void setSuccessHtmlFile(QString filePath); - -Q_SIGNALS: - void verificationReceived(QMultiMap); - - -private: - KQOAuthAuthReplyServerPrivate * const d_ptr; - Q_DECLARE_PRIVATE(KQOAuthAuthReplyServer); - Q_DISABLE_COPY(KQOAuthAuthReplyServer); - - -}; - -#endif // KQOAUTHAUTHREPLYSERVER_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver_p.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver_p.h deleted file mode 100644 index 8da4d582e3..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver_p.h +++ /dev/null @@ -1,53 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see - */ -// Note this class shouldn't be copied or used and the implementation might change later. -#ifndef KQOAUTHAUTHREPLYSERVER_P_H -#define KQOAUTHAUTHREPLYSERVER_P_H - -#include "kqoauthauthreplyserver.h" -#include -#include - -class KQOAUTH_EXPORT KQOAuthAuthReplyServerPrivate: public QObject -{ - Q_OBJECT -public: - KQOAuthAuthReplyServerPrivate( KQOAuthAuthReplyServer * parent ); - ~KQOAuthAuthReplyServerPrivate(); - QMultiMap parseQueryParams(QByteArray *sdata); - -public Q_SLOTS: - void onIncomingConnection(); - void onBytesReady(); - -public: - KQOAuthAuthReplyServer * q_ptr; - Q_DECLARE_PUBLIC(KQOAuthAuthReplyServer); - QTcpSocket *socket; - QString localFile; -private: - bool handlingRedirect; -}; - -#endif // KQOAUTHAUTHREPLYSERVER_P_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthglobals.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthglobals.h deleted file mode 100644 index 203716f764..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthglobals.h +++ /dev/null @@ -1,52 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see - */ -#ifndef KQOAUTHGLOBALS_H -#define KQOAUTHGLOBALS_H - -#include - -#if defined(KQOAUTH) -# define KQOAUTH_EXPORT Q_DECL_EXPORT -#else -# define KQOAUTH_EXPORT Q_DECL_IMPORT -#endif - -//////////// Static constant definitions /////////// -const QString OAUTH_KEY_CONSUMER("oauth_consumer"); -const QString OAUTH_KEY_CONSUMER_KEY("oauth_consumer_key"); -const QString OAUTH_KEY_TOKEN("oauth_token"); -const QString OAUTH_KEY_TOKEN_SECRET("oauth_token_secret"); -const QString OAUTH_KEY_SIGNATURE_METHOD("oauth_signature_method"); -const QString OAUTH_KEY_TIMESTAMP("oauth_timestamp"); -const QString OAUTH_KEY_NONCE("oauth_nonce"); -const QString OAUTH_KEY_SIGNATURE("oauth_signature"); -const QString OAUTH_KEY_CALLBACK("oauth_callback"); -const QString OAUTH_KEY_VERIFIER("oauth_verifier"); -const QString OAUTH_KEY_VERSION("oauth_version"); -const QString OAUTH2_KEY_CLIENT_ID("client_id"); -const QString OAUTH2_KEY_CLIENT_SECRET("client_secret"); -const QString OAUTH2_KEY_REDIRECT_URI("redirect_uri"); -const QString OAUTH2_KEY_RESPONSE_TYPE("response_type"); - -#endif // KQOAUTHGLOBALS_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.cpp b/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.cpp deleted file mode 100644 index 50ae91e211..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.cpp +++ /dev/null @@ -1,729 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see - */ -#include -#include - -#include "kqoauthmanager.h" -#include "kqoauthmanager_p.h" - - -////////////// Private d_ptr implementation //////////////// - -KQOAuthManagerPrivate::KQOAuthManagerPrivate(KQOAuthManager *parent) : - error(KQOAuthManager::NoError) , - r(0) , - opaqueRequest(new KQOAuthRequest) , - q_ptr(parent) , - callbackServer(new KQOAuthAuthReplyServer(parent)) , - isVerified(false) , - isAuthorized(false) , - autoAuth(false), - networkManager(new QNetworkAccessManager), - managerUserSet(false) -{ - -} - -KQOAuthManagerPrivate::~KQOAuthManagerPrivate() { - delete opaqueRequest; - opaqueRequest = 0; - - if (!managerUserSet) { - delete networkManager; - networkManager = 0; - } -} - -QList< QPair > KQOAuthManagerPrivate::createQueryParams(const KQOAuthParameters &requestParams) { - QList requestKeys = requestParams.keys(); - QList requestValues = requestParams.values(); - - QList< QPair > result; - for(int i=0; i KQOAuthManagerPrivate::createTokensFromResponse(QByteArray reply) { - QMultiMap result; - QString replyString(reply); - - QStringList parameterPairs = replyString.split('&', QString::SkipEmptyParts); - foreach (const QString ¶meterPair, parameterPairs) { - QStringList parameter = parameterPair.split('='); - result.insert(parameter.value(0), parameter.value(1)); - } - - return result; -} - -bool KQOAuthManagerPrivate::setSuccessfulRequestToken(const QMultiMap &request) { - if (currentRequestType == KQOAuthRequest::TemporaryCredentials) { - hasTemporaryToken = (!QString(request.value("oauth_token")).isEmpty() && !QString(request.value("oauth_token_secret")).isEmpty()); - } else { - return false; - } - - if (hasTemporaryToken) { - requestToken = QUrl::fromPercentEncoding( QString(request.value("oauth_token")).toLocal8Bit() ); - requestTokenSecret = QUrl::fromPercentEncoding( QString(request.value("oauth_token_secret")).toLocal8Bit() ); - results = request; - } - - return hasTemporaryToken; -} - -bool KQOAuthManagerPrivate::setSuccessfulAuthorized(const QMultiMap &request ) { - if (currentRequestType == KQOAuthRequest::AccessToken) { - isAuthorized = (!QString(request.value("oauth_token")).isEmpty() && !QString(request.value("oauth_token_secret")).isEmpty()); - } else { - return false; - } - - if (isAuthorized) { - requestToken = QUrl::fromPercentEncoding( QString(request.value("oauth_token")).toLocal8Bit() ); - requestTokenSecret = QUrl::fromPercentEncoding( QString(request.value("oauth_token_secret")).toLocal8Bit() ); - results = request; - } - - return isAuthorized; -} - -void KQOAuthManagerPrivate::emitTokens() { - Q_Q(KQOAuthManager); - - if (this->requestToken.isEmpty() || this->requestTokenSecret.isEmpty()) { - error = KQOAuthManager::RequestUnauthorized; - } - - if (currentRequestType == KQOAuthRequest::TemporaryCredentials) { - // Signal that we are ready to use the protected resources. - emit q->temporaryTokenReceived(this->requestToken, this->requestTokenSecret, this->results); - } - - if (currentRequestType == KQOAuthRequest::AccessToken) { - // Signal that we are ready to use the protected resources. - emit q->accessTokenReceived(this->requestToken, this->requestTokenSecret, this->results); - } - - emit q->receivedToken(this->requestToken, this->requestTokenSecret); -} - -bool KQOAuthManagerPrivate::setupCallbackServer() { - return callbackServer->listen(); -} - - -/////////////// Public implementation //////////////// - -KQOAuthManager::KQOAuthManager(QObject *parent) : - QObject(parent) , - d_ptr(new KQOAuthManagerPrivate(this)) -{ - -} - -KQOAuthManager::~KQOAuthManager() -{ - delete d_ptr; -} - -void KQOAuthManager::executeRequest(KQOAuthRequest *request) { - Q_D(KQOAuthManager); - - d->r = request; - - if (request == 0) { - qWarning() << "Request is NULL. Cannot proceed."; - d->error = KQOAuthManager::RequestError; - return; - } - - if (!request->requestEndpoint().isValid()) { - qDebug() << request->requestEndpoint(); - qWarning() << "Request endpoint URL is not valid. Cannot proceed."; - d->error = KQOAuthManager::RequestEndpointError; - return; - } - - if (!request->isValid()) { - qWarning() << "Request is not valid. Cannot proceed."; - d->error = KQOAuthManager::RequestValidationError; - return; - } - - d->currentRequestType = request->requestType(); - - QNetworkRequest networkRequest; - networkRequest.setUrl( request->requestEndpoint() ); - - if (d->autoAuth && d->currentRequestType == KQOAuthRequest::TemporaryCredentials) { - d->setupCallbackServer(); - connect(d->callbackServer, SIGNAL(verificationReceived(QMultiMap)), - this, SLOT( onVerificationReceived(QMultiMap))); - - QString serverString = "http://localhost:"; - serverString.append(QString::number(d->callbackServer->serverPort())); - request->setCallbackUrl(QUrl(serverString)); - qDebug() << serverString; - } - - // And now fill the request with "Authorization" header data. - QList requestHeaders = request->requestParameters(); - QByteArray authHeader; - - bool first = true; - foreach (const QByteArray header, requestHeaders) { - if (!first) { - authHeader.append(", "); - } else { - authHeader.append("OAuth "); - first = false; - } - - authHeader.append(header); - } - networkRequest.setRawHeader("Authorization", authHeader); - - connect(d->networkManager, SIGNAL(finished(QNetworkReply *)), - this, SLOT(onRequestReplyReceived(QNetworkReply *)), Qt::UniqueConnection); - disconnect(d->networkManager, SIGNAL(finished(QNetworkReply *)), - this, SLOT(onAuthorizedRequestReplyReceived(QNetworkReply *))); - - if (request->httpMethod() == KQOAuthRequest::GET) { - // Get the requested additional params as a list of pairs we can give QUrl - QList< QPair > urlParams = d->createQueryParams(request->additionalParameters()); - - // Take the original URL and append the query params to it. - QUrl urlWithParams = networkRequest.url(); - urlWithParams.setQueryItems(urlParams); - networkRequest.setUrl(urlWithParams); - - // Submit the request including the params. - QNetworkReply *reply = d->networkManager->get(networkRequest); - reply->ignoreSslErrors(); - connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), - this, SLOT(slotError(QNetworkReply::NetworkError))); - - } else if (request->httpMethod() == KQOAuthRequest::POST) { - - networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, request->contentType()); - - qDebug() << networkRequest.rawHeaderList(); - qDebug() << networkRequest.rawHeader("Authorization"); - qDebug() << networkRequest.rawHeader("Content-Type"); - - QNetworkReply *reply; - if (request->contentType() == "application/x-www-form-urlencoded") { - reply = d->networkManager->post(networkRequest, request->requestBody()); - } else { - reply = d->networkManager->post(networkRequest, request->rawData()); - } - reply->ignoreSslErrors(); - - connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), - this, SLOT(slotError(QNetworkReply::NetworkError))); - } - - d->r->requestTimerStart(); -} - -void KQOAuthManager::executeAuthorizedRequest(KQOAuthRequest *request, int id) { - Q_D(KQOAuthManager); - - d->r = request; - - if (request == 0) { - qWarning() << "Request is NULL. Cannot proceed."; - d->error = KQOAuthManager::RequestError; - return; - } - - if (!request->requestEndpoint().isValid()) { - qDebug() << request->requestEndpoint(); - qWarning() << "Request endpoint URL is not valid. Cannot proceed."; - d->error = KQOAuthManager::RequestEndpointError; - return; - } - - if (!request->isValid()) { - qWarning() << "Request is not valid. Cannot proceed."; - d->error = KQOAuthManager::RequestValidationError; - return; - } - - d->currentRequestType = request->requestType(); - - QNetworkRequest networkRequest; - networkRequest.setUrl( request->requestEndpoint() ); - - if ( d->currentRequestType != KQOAuthRequest::AuthorizedRequest){ - qWarning() << "Not Authorized Request. Cannot proceed"; - d->error = KQOAuthManager::RequestError; - return; - } - - if(request->oauthMethod() != KQOAuthRequest::OAUTH2) { - // And now fill the request with "Authorization" header data. - QList requestHeaders = request->requestParameters(); - QByteArray authHeader; - - bool first = true; - foreach (const QByteArray header, requestHeaders) { - if (!first) { - authHeader.append(", "); - } else { - authHeader.append("OAuth "); - first = false; - } - - authHeader.append(header); - } - networkRequest.setRawHeader("Authorization", authHeader); - } - - - disconnect(d->networkManager, SIGNAL(finished(QNetworkReply *)), - this, SLOT(onRequestReplyReceived(QNetworkReply *))); - connect(d->networkManager, SIGNAL(finished(QNetworkReply *)), - this, SLOT(onAuthorizedRequestReplyReceived(QNetworkReply*)), Qt::UniqueConnection); - - if (request->httpMethod() == KQOAuthRequest::GET) { - // Get the requested additional params as a list of pairs we can give QUrl - QList< QPair > urlParams = d->createQueryParams(request->additionalParameters()); - - // Take the original URL and append the query params to it. - QUrl urlWithParams = networkRequest.url(); - urlWithParams.setQueryItems(urlParams); - networkRequest.setUrl(urlWithParams); - qDebug() << networkRequest.url(); - - // Submit the request including the params. - QNetworkReply *reply = d->networkManager->get(networkRequest); - reply->ignoreSslErrors(); - connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), - this, SLOT(slotError(QNetworkReply::NetworkError))); - - } else if (request->httpMethod() == KQOAuthRequest::POST) { - - networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, request->contentType()); - - qDebug() << networkRequest.rawHeaderList(); - qDebug() << networkRequest.rawHeader("Authorization"); - qDebug() << networkRequest.rawHeader("Content-Type"); - - QNetworkReply *reply; - if (request->contentType() == "application/x-www-form-urlencoded") { - reply = d->networkManager->post(networkRequest, request->requestBody()); - } else { - reply = d->networkManager->post(networkRequest, request->rawData()); - } - reply->ignoreSslErrors(); - - d->requestIds.insert(reply, id); - - connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), - this, SLOT(slotError(QNetworkReply::NetworkError))); - } - - d->r->requestTimerStart(); -} - - -void KQOAuthManager::setHandleUserAuthorization(bool set) { - Q_D(KQOAuthManager); - - d->autoAuth = set; -} - -bool KQOAuthManager::hasTemporaryToken() { - Q_D(KQOAuthManager); - - return d->hasTemporaryToken; -} - -bool KQOAuthManager::isVerified() { - Q_D(KQOAuthManager); - - return d->isVerified; -} - -bool KQOAuthManager::isAuthorized() { - Q_D(KQOAuthManager); - - return d->isAuthorized; -} - -KQOAuthManager::KQOAuthError KQOAuthManager::lastError() { - Q_D(KQOAuthManager); - - return d->error; -} - -void KQOAuthManager::setNetworkManager(QNetworkAccessManager *manager) { - Q_D(KQOAuthManager); - - if (manager == 0) { - d->error = KQOAuthManager::ManagerError; - return; - } - - if (!d->managerUserSet) { - delete d->networkManager; - } - - d->managerUserSet = true; - d->networkManager = manager; -} - -QNetworkAccessManager * KQOAuthManager::networkManager() const { - Q_D(const KQOAuthManager); - - if (d->managerUserSet) { - return d->networkManager; - } else { - return NULL; - } - -} - -void KQOAuthManager::setSuccessHtmlFile(QString file) { - Q_D(KQOAuthManager); - d->successHtmlFile = file; - d->callbackServer->setSuccessHtmlFile(file); -} - - -//////////// Public convenience API ///////////// -void KQOAuthManager::getOauth2UserAuthorization(QUrl authorizationEndpoint, QString consumerKey, const KQOAuthParameters &additionalParams) { - Q_D(KQOAuthManager); - - d->setupCallbackServer(); - connect(d->callbackServer, SIGNAL(verificationReceived(QMultiMap)), - this, SLOT( onOauth2VerificationReceived(QMultiMap))); - - QString serverString = "http://localhost:"; - serverString.append(QString::number(d->callbackServer->serverPort())); - QUrl openWebPageUrl(authorizationEndpoint.toString(), QUrl::StrictMode); - openWebPageUrl.addQueryItem(OAUTH2_KEY_CLIENT_ID, consumerKey); - openWebPageUrl.addQueryItem(OAUTH2_KEY_RESPONSE_TYPE, "token"); - openWebPageUrl.addQueryItem(OAUTH2_KEY_REDIRECT_URI, serverString); - if(additionalParams.size() > 0) { - QList< QPair > urlParams = d->createQueryParams(additionalParams); - for(int i=0; i < urlParams.length(); i++){ - openWebPageUrl.addQueryItem(urlParams[i].first, urlParams[i].second); - } - } - qDebug() << openWebPageUrl.toString(); - QDesktopServices::openUrl(openWebPageUrl); - //navigator_invoke(openWebPageUrl.toString().toStdString().c_str(),0); -} - -QUrl KQOAuthManager::getUserAuthorizationUrl(QUrl authorizationEndpoint) { - Q_D(KQOAuthManager); - - if (!d->hasTemporaryToken) { - qWarning() << "No temporary tokens retreieved. Cannot get user authorization."; - d->error = KQOAuthManager::RequestUnauthorized; - return QUrl(); - } - - if (!authorizationEndpoint.isValid()) { - qWarning() << "Authorization endpoint not valid. Cannot proceed."; - d->error = KQOAuthManager::RequestEndpointError; - return QUrl(); - } - - d->error = KQOAuthManager::NoError; - - QPair tokenParam = qMakePair(QString("oauth_token"), QString(d->requestToken)); - QUrl openWebPageUrl(authorizationEndpoint.toString(), QUrl::StrictMode); - openWebPageUrl.addQueryItem(tokenParam.first, tokenParam.second); - - qDebug() << openWebPageUrl.toString(); - return openWebPageUrl; -} - -void KQOAuthManager::getUserAuthorization(QUrl authorizationEndpoint) { - QUrl openWebPageUrl = getUserAuthorizationUrl(authorizationEndpoint); - - if(!openWebPageUrl.isEmpty()) { - // Open the user's default browser to the resource authorization page provided - // by the service. - - QDesktopServices::openUrl(openWebPageUrl); - //navigator_invoke(openWebPageUrl.toString().toStdString().c_str(),0); - } -} - -void KQOAuthManager::getUserAccessTokens(QUrl accessTokenEndpoint) { - Q_D(KQOAuthManager); - - if (!d->isVerified) { - qWarning() << "Not verified. Cannot get access tokens."; - d->error = KQOAuthManager::RequestUnauthorized; - return; - } - - if (!accessTokenEndpoint.isValid()) { - qWarning() << "Endpoint for access token exchange is not valid. Cannot proceed."; - d->error = KQOAuthManager::RequestEndpointError; - return; - } - - d->error = KQOAuthManager::NoError; - - d->opaqueRequest->clearRequest(); - d->opaqueRequest->initRequest(KQOAuthRequest::AccessToken, accessTokenEndpoint); - d->opaqueRequest->setToken(d->requestToken); - d->opaqueRequest->setTokenSecret(d->requestTokenSecret); - d->opaqueRequest->setVerifier(d->requestVerifier); - d->opaqueRequest->setConsumerKey(d->consumerKey); - d->opaqueRequest->setConsumerSecretKey(d->consumerKeySecret); - - executeRequest(d->opaqueRequest); -} - -void KQOAuthManager::sendAuthorizedRequest(QUrl requestEndpoint, const KQOAuthParameters &requestParameters) { - Q_D(KQOAuthManager); - - if (!d->isAuthorized) { - qWarning() << "No access tokens retrieved. Cannot send authorized requests."; - d->error = KQOAuthManager::RequestUnauthorized; - return; - } - - if (!requestEndpoint.isValid()) { - qWarning() << "Endpoint for authorized request is not valid. Cannot proceed."; - d->error = KQOAuthManager::RequestEndpointError; - return; - } - - d->error = KQOAuthManager::NoError; - - d->opaqueRequest->clearRequest(); - d->opaqueRequest->initRequest(KQOAuthRequest::AuthorizedRequest, requestEndpoint); - d->opaqueRequest->setAdditionalParameters(requestParameters); - d->opaqueRequest->setToken(d->requestToken); - d->opaqueRequest->setTokenSecret(d->requestTokenSecret); - d->opaqueRequest->setConsumerKey(d->consumerKey); - d->opaqueRequest->setConsumerSecretKey(d->consumerKeySecret); - - executeRequest(d->opaqueRequest); -} - - -/////////////// Private slots ////////////////// - -void KQOAuthManager::onRequestReplyReceived( QNetworkReply *reply ) { - Q_D(KQOAuthManager); - - QNetworkReply::NetworkError networkError = reply->error(); - switch (networkError) { - case QNetworkReply::NoError: - d->error = KQOAuthManager::NoError; - break; - - case QNetworkReply::ContentAccessDenied: - case QNetworkReply::AuthenticationRequiredError: - d->error = KQOAuthManager::RequestUnauthorized; - break; - - default: - d->error = KQOAuthManager::NetworkError; - break; - } - - // Let's disconnect this slot first - /* - disconnect(d->networkManager, SIGNAL(finished(QNetworkReply *)), - this, SLOT(onRequestReplyReceived(QNetworkReply *))); - */ - - // Read the content of the reply from the network. - QByteArray networkReply = reply->readAll(); - - // Stop any timer we have set on the request. - d->r->requestTimerStop(); - - // Just don't do anything if we didn't get anything useful. - if(networkReply.isEmpty()) { - reply->deleteLater(); - return; - } - QMultiMap responseTokens; - - // We need to emit the signal even if we got an error. - if (d->error != KQOAuthManager::NoError) { - reply->deleteLater(); - emit requestReady(networkReply); - d->emitTokens(); - return; - } - - responseTokens = d->createTokensFromResponse(networkReply); - d->opaqueRequest->clearRequest(); - d->opaqueRequest->setHttpMethod(KQOAuthRequest::POST); // XXX FIXME: Convenient API does not support GET - if (!d->isAuthorized || !d->isVerified) { - if (d->setSuccessfulRequestToken(responseTokens)) { - qDebug() << "Successfully got request tokens."; - d->consumerKey = d->r->consumerKeyForManager(); - d->consumerKeySecret = d->r->consumerKeySecretForManager(); - d->opaqueRequest->setSignatureMethod(KQOAuthRequest::HMAC_SHA1); - d->opaqueRequest->setCallbackUrl(d->r->callbackUrlForManager()); - - d->emitTokens(); - - } else if (d->setSuccessfulAuthorized(responseTokens)) { - qDebug() << "Successfully got access tokens."; - d->opaqueRequest->setSignatureMethod(KQOAuthRequest::HMAC_SHA1); - - d->emitTokens(); - } else if (d->currentRequestType == KQOAuthRequest::AuthorizedRequest) { - emit authorizedRequestDone(); - } - } - - emit requestReady(networkReply); - - reply->deleteLater(); // We need to clean this up, after the event processing is done. -} - -void KQOAuthManager::onAuthorizedRequestReplyReceived( QNetworkReply *reply ) { - Q_D(KQOAuthManager); - - QNetworkReply::NetworkError networkError = reply->error(); - switch (networkError) { - case QNetworkReply::NoError: - d->error = KQOAuthManager::NoError; - break; - - case QNetworkReply::ContentAccessDenied: - case QNetworkReply::AuthenticationRequiredError: - d->error = KQOAuthManager::RequestUnauthorized; - break; - - default: - d->error = KQOAuthManager::NetworkError; - break; - } - - /* - disconnect(d->networkManager, SIGNAL(finished(QNetworkReply *)), - this, SLOT(onAuthorizedRequestReplyReceived(QNetworkReply *))); - */ - - // Read the content of the reply from the network. - QByteArray networkReply = reply->readAll(); - - // Stop any timer we have set on the request. - d->r->requestTimerStop(); - - // Just don't do anything if we didn't get anything useful. - if(networkReply.isEmpty()) { - reply->deleteLater(); - return; - } - - // We need to emit the signal even if we got an error. - if (d->error != KQOAuthManager::NoError) { - qWarning() << "Network reply error"; - return; - } - - - d->opaqueRequest->clearRequest(); - d->opaqueRequest->setHttpMethod(KQOAuthRequest::POST); // XXX FIXME: Convenient API does not support GET - if (d->currentRequestType == KQOAuthRequest::AuthorizedRequest) { - emit authorizedRequestDone(); - } - - int id = d->requestIds.take(reply); - emit authorizedRequestReady(networkReply, id); - reply->deleteLater(); -} - - -void KQOAuthManager::onVerificationReceived(QMultiMap response) { - Q_D(KQOAuthManager); - - QString token = response.value("oauth_token"); - QString verifier = response.value("oauth_verifier"); - if (verifier.isEmpty()) { - d->error = KQOAuthManager::RequestUnauthorized; - } - - verifier = QUrl::fromPercentEncoding(verifier.toUtf8()); // We get the raw URL response here so we need to convert it back - // to plain string so we can percent encode it again later in requests. - - if (d->error == KQOAuthManager::NoError) { - d->requestVerifier = verifier; - d->isVerified = true; - } - - emit authorizationReceived(token, verifier); -} - -void KQOAuthManager::onOauth2VerificationReceived(QMultiMap response) { - Q_D(KQOAuthManager); - - foreach(QString key, response.keys()){ - qDebug() << key; - } - - QString token = response.value("access_token"); - if (token.isEmpty()) { - d->error = KQOAuthManager::RequestUnauthorized; - } - - if (d->error == KQOAuthManager::NoError) { - d->isVerified = true; - } - - emit authorizationReceived(token, NULL); -} - -void KQOAuthManager::slotError(QNetworkReply::NetworkError error) { - Q_UNUSED(error) - Q_D(KQOAuthManager); - - d->error = KQOAuthManager::NetworkError; - QByteArray emptyResponse; - emit requestReady(emptyResponse); - emit authorizedRequestDone(); - - QNetworkReply *reply = qobject_cast(sender()); - d->requestIds.remove(reply); - reply->deleteLater(); -} - -void KQOAuthManager::onSslError(QNetworkReply *reply, const QList &errors) { - Q_UNUSED(errors); - reply->ignoreSslErrors(); -} - diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.h deleted file mode 100644 index a99b870f00..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.h +++ /dev/null @@ -1,205 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see - */ -#ifndef KQOAUTHMANAGER_H -#define KQOAUTHMANAGER_H - -#include -#include -#include - -#include "kqoauthrequest.h" - -class KQOAuthRequest; -class KQOAuthManagerThread; -class KQOAuthManagerPrivate; -class QNetworkAccessManager; -class QUrl; -class QByteArray; -class KQOAUTH_EXPORT KQOAuthManager : public QObject -{ - Q_OBJECT -public: - - enum KQOAuthError { - NoError, // No error - NetworkError, // Network error: timeout, cannot connect. - RequestEndpointError, // Request endpoint is not valid. - RequestValidationError, // Request is not valid: some parameter missing? - RequestUnauthorized, // Authorization error: trying to access a resource without tokens. - RequestError, // The given request to KQOAuthManager is invalid: NULL?, - ManagerError // Manager error, cannot use for sending requests. - }; - - explicit KQOAuthManager(QObject *parent = 0); - ~KQOAuthManager(); - - KQOAuthError lastError(); - - /** - * The manager executes the given request. It takes the HTTP parameters from the - * request and uses QNetworkAccessManager to submit the HTTP request to the net. - * When the request is done it will emit signal requestReady(QByteArray networkReply). - * NOTE: At the moment there is no timeout for the request. - */ - void executeRequest(KQOAuthRequest *request); - void executeAuthorizedRequest(KQOAuthRequest *request, int id); - /** - * Indicates to the user that KQOAuthManager should handle user authorization by - * opening the user's default browser and parsing the reply from the service. - * By setting the parameter to true, KQOAuthManager will store intermediate results - * of the OAuth 1.0 process in its own opaque request. This information is used in - * the user authorization process and also when calling sendAuthorizedRequest(). - * NOTE: You need to set this to true if you want to use getUserAccessTokens() or - * sendAuthorizedRequest(). - */ - void setHandleUserAuthorization(bool set); - - /** - * Returns true if the KQOAuthManager has retrieved the oauth_token value. Otherwise - * return false. - */ - bool hasTemporaryToken(); - /** - * Returns true if the user has authorized us to use the protected resources. Otherwise - * returns false. - * NOTE: In order for KQOAuthManager to know if the user has authorized us to use the - * protected resources, KQOAuthManager must be in control of the user authorization - * process. Hence, this returns true if setHandleUserAuthorization() is set to true - * and the user is authorized with getUserAuthorization(). - */ - bool isVerified(); - /** - * Returns true if KQOAuthManager has the access token and hence can access the protected - * resources. Otherwise returns false. - * NOTE: In order for KQOAuthManager to know if we have access to protected resource - * KQOAuthManager must be in control of the user authorization process and requesting - * the acess token. Hence, this returns true if setHandleUserAuthorization() is set to true - * and the user is authorized with getUserAuthorization() and the access token must be retrieved - * with getUserAccessTokens. - */ - bool isAuthorized(); - - /** - * Sets the file path string that the local server will serve on a successful authentication. This will generally direct - * your user to go back to your application and continue using the app. - */ - void setSuccessHtmlFile(QString filePath); - - /** - * This is a convenience API for authorizing the user. - * The call will verify that a temporary token was received and return the url that the user needs to - * use to authorize the app, it will not open the user's default browser. - */ - QUrl getUserAuthorizationUrl(QUrl authorizationEndpoint); - /** - * This is a convenience API for authorizing the user. - * The call will open the user's default browser, setup a local HTTP server and parse the reply from the - * service after the user has authorized us to access protected resources. If the user authorizes - * us to access protected resources, the verifier token is stored in KQOAuthManager for further use. - * In order to use this method, you must set setHandleUserAuthorization() to true. - */ - void getUserAuthorization(QUrl authorizationEndpoint); - /** - * This is a convenience API for retrieving the access token in exchange for the temporary token and the - * verifier. - * This call will create a KQOAuthRequest and use the previously stored temporary token and verifier to - * exchange for the access token, which will be used to access the protected resources. - * Note that in order to use this method, KQOAuthManager must be in control of the user authorization process. - * Set setHandleUserAuthorization() to true and retrieve user authorization with void getUserAuthorization. - */ - void getUserAccessTokens(QUrl accessTokenEndpoint); - /** - * This is a method for bypassing all the oauth1 auth process and using the browser based oauth2 flow. This will - * launch the browser and set the callback url pointed to a localhost url. Make sure your oauth2 service supports redirect_uri param. - * Add any other params in the additionalParams args like scope or state or any other - */ - void getOauth2UserAuthorization(QUrl authorizationEndpoint, QString consumerKey, const KQOAuthParameters &additionalParams); - /** - * Sends a request to the protected resources. Parameters for the request are service specific and - * are given to the 'requestParameters' as parameters. - * Note that in order to use this method, KQOAuthManager must be in control of the user authorization process. - * Set setHandleUserAuthorization() to true and retrieve user authorization with void getUserAuthorization. - */ - void sendAuthorizedRequest(QUrl requestEndpoint, const KQOAuthParameters &requestParameters); - - /** - * Sets a custom QNetworkAccessManager to handle network requests. This method can be useful if the - * application is using some proxy settings for example. - * The application is responsible for deleting this manager. KQOAuthManager will not delete any - * previously given manager. - * If the manager is NULL, the manager will not be set and the KQOAuthManager::Error. - * If no manager is given, KQOAuthManager will use the default one it will create by itself. - */ - void setNetworkManager(QNetworkAccessManager *manager); - - /** - * Returns the given QNetworkAccessManager. Returns NULL if none is given. - */ - QNetworkAccessManager* networkManager() const; - -Q_SIGNALS: - // This signal will be emitted after each request has got a reply. - // Parameter is the raw response from the service. - void requestReady(QByteArray networkReply); - - void authorizedRequestReady(QByteArray networkReply, int id); - - // This signal will be emited when we have an request tokens available - // (either temporary resource tokens, or authorization tokens). - void receivedToken(QString oauth_token, QString oauth_token_secret); // oauth_token, oauth_token_secret - - // This signal is emited when temporary tokens are returned from the service. - // Note that this signal is also emited in case temporary tokens are not available. - void temporaryTokenReceived(QString oauth_token, QString oauth_token_secret, QMultiMap results); // oauth_token, oauth_token_secret - - // This signal is emited when the user has authenticated the application to - // communicate with the protected resources. Next we need to exchange the - // temporary tokens for access tokens. - // Note that this signal is also emited if user denies access. - void authorizationReceived(QString oauth_token, QString oauth_verifier); // oauth_token, oauth_verifier - - // This signal is emited when access tokens are received from the service. We are - // ready to start communicating with the protected resources. - void accessTokenReceived(QString oauth_token, QString oauth_token_secret, QMultiMap results); // oauth_token, oauth_token_secret - - // This signal is emited when the authorized request is done. - // This ends the kQOAuth interactions. - void authorizedRequestDone(); - -private Q_SLOTS: - void onRequestReplyReceived( QNetworkReply *reply ); - void onAuthorizedRequestReplyReceived( QNetworkReply *reply ); - void onVerificationReceived(QMultiMap response); - void onOauth2VerificationReceived(QMultiMap response); - void slotError(QNetworkReply::NetworkError error); - void onSslError(QNetworkReply *reply, const QList &errors); - -private: - KQOAuthManagerPrivate *d_ptr; - Q_DECLARE_PRIVATE(KQOAuthManager); - Q_DISABLE_COPY(KQOAuthManager); - -}; - -#endif // KQOAUTHMANAGER_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager_p.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager_p.h deleted file mode 100644 index cd2c0a1e05..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager_p.h +++ /dev/null @@ -1,80 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see - */ -#ifndef KQOAUTHMANAGER_P_H -#define KQOAUTHMANAGER_P_H - -#include "kqoauthauthreplyserver.h" -#include "kqoauthrequest.h" - -class KQOAUTH_EXPORT KQOAuthManagerPrivate { - -public: - KQOAuthManagerPrivate(KQOAuthManager *parent); - ~KQOAuthManagerPrivate(); - - QList< QPair > createQueryParams(const KQOAuthParameters &requestParams); - QMultiMap createTokensFromResponse(QByteArray reply); - bool setSuccessfulRequestToken(const QMultiMap &request); - bool setSuccessfulAuthorized(const QMultiMap &request); - void emitTokens(); - bool setupCallbackServer(); - - KQOAuthManager::KQOAuthError error; - KQOAuthRequest *r; // This request is used to cache the user sent request. - KQOAuthRequest *opaqueRequest; // This request is used to creating opaque convenience requests for the user. - KQOAuthManager * const q_ptr; - - /** - * The items below are needed in order to store the state of the manager and - * by that be able to do convenience operations for the user. - */ - KQOAuthRequest::RequestType currentRequestType; - - // Variables we store here for opaque request handling. - // NOTE: The variables are labeled the same for both access token request - // and protected resource access. - QString requestToken; - QString requestTokenSecret; - QString consumerKey; - QString consumerKeySecret; - QString requestVerifier; - QMultiMap results; - - - QString successHtmlFile; - - KQOAuthAuthReplyServer *callbackServer; - - bool hasTemporaryToken; - bool isVerified; - bool isAuthorized; - bool autoAuth; - QNetworkAccessManager *networkManager; - bool managerUserSet; - QMap requestIds; - - Q_DECLARE_PUBLIC(KQOAuthManager); -}; - -#endif // KQOAUTHMANAGER_P_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest.cpp b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest.cpp deleted file mode 100644 index e81b56dfee..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest.cpp +++ /dev/null @@ -1,625 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see - */ -#include -#include -#include -#include -#include - -#include -#include - -#include "kqoauthrequest.h" -#include "kqoauthrequest_p.h" -#include "kqoauthutils.h" -#include "kqoauthglobals.h" - - -//////////// Private d_ptr implementation ///////// - -KQOAuthRequestPrivate::KQOAuthRequestPrivate() : - timeout(0) -{ - -} - -KQOAuthRequestPrivate::~KQOAuthRequestPrivate() -{ - -} - -// This method will not include the "oauthSignature" paramater, since it is calculated from these parameters. -void KQOAuthRequestPrivate::prepareRequest() { - - // If parameter list is not empty, we don't want to insert these values by - // accident a second time. So giving up. - if( !requestParameters.isEmpty() ) { - return; - } - - switch ( requestType ) { - case KQOAuthRequest::TemporaryCredentials: - requestParameters.append( qMakePair( OAUTH_KEY_CALLBACK, oauthCallbackUrl.toString()) ); // This is so ugly that it is almost beautiful. - requestParameters.append( qMakePair( OAUTH_KEY_SIGNATURE_METHOD, oauthSignatureMethod) ); - requestParameters.append( qMakePair( OAUTH_KEY_CONSUMER_KEY, oauthConsumerKey )); - requestParameters.append( qMakePair( OAUTH_KEY_VERSION, oauthVersion )); - requestParameters.append( qMakePair( OAUTH_KEY_TIMESTAMP, this->oauthTimestamp() )); - requestParameters.append( qMakePair( OAUTH_KEY_NONCE, this->oauthNonce() )); - break; - - case KQOAuthRequest::AccessToken: - requestParameters.append( qMakePair( OAUTH_KEY_SIGNATURE_METHOD, oauthSignatureMethod )); - requestParameters.append( qMakePair( OAUTH_KEY_CONSUMER_KEY, oauthConsumerKey )); - requestParameters.append( qMakePair( OAUTH_KEY_VERSION, oauthVersion )); - requestParameters.append( qMakePair( OAUTH_KEY_TIMESTAMP, this->oauthTimestamp() )); - requestParameters.append( qMakePair( OAUTH_KEY_NONCE, this->oauthNonce() )); - requestParameters.append( qMakePair( OAUTH_KEY_VERIFIER, oauthVerifier )); - requestParameters.append( qMakePair( OAUTH_KEY_TOKEN, oauthToken )); - break; - - case KQOAuthRequest::AuthorizedRequest: - requestParameters.append( qMakePair( OAUTH_KEY_SIGNATURE_METHOD, oauthSignatureMethod )); - requestParameters.append( qMakePair( OAUTH_KEY_CONSUMER_KEY, oauthConsumerKey )); - requestParameters.append( qMakePair( OAUTH_KEY_VERSION, oauthVersion )); - requestParameters.append( qMakePair( OAUTH_KEY_TIMESTAMP, this->oauthTimestamp() )); - requestParameters.append( qMakePair( OAUTH_KEY_NONCE, this->oauthNonce() )); - requestParameters.append( qMakePair( OAUTH_KEY_TOKEN, oauthToken )); - break; - - default: - break; - } -} - -void KQOAuthRequestPrivate::signRequest() { - QString signature = this->oauthSignature(); - requestParameters.append( qMakePair( OAUTH_KEY_SIGNATURE, signature) ); -} - -QString KQOAuthRequestPrivate::oauthSignature() { - /** - * http://oauth.net/core/1.0/#anchor16 - * The HMAC-SHA1 signature method uses the HMAC-SHA1 signature algorithm as defined in [RFC2104] where the - * Signature Base String is the text and the key is the concatenated values (each first encoded per Parameter - * Encoding) of the Consumer Secret and Token Secret, separated by an ‘&’ character (ASCII code 38) even if empty. - **/ - QByteArray baseString = this->requestBaseString(); - - QString secret = QString(QUrl::toPercentEncoding(oauthConsumerSecretKey)) + "&" + QString(QUrl::toPercentEncoding(oauthTokenSecret)); - QString signature = KQOAuthUtils::hmac_sha1(baseString, secret); - - if (debugOutput) { - qDebug() << "========== KQOAuthRequest has the following signature:"; - qDebug() << " * Signature : " << QUrl::toPercentEncoding(signature) << "\n"; - } - return QString( QUrl::toPercentEncoding(signature) ); -} - -bool normalizedParameterSort(const QPair &left, const QPair &right) { - QString keyLeft = left.first; - QString valueLeft = left.second; - QString keyRight = right.first; - QString valueRight = right.second; - - if(keyLeft == keyRight) { - return (valueLeft < valueRight); - } else { - return (keyLeft < keyRight); - } -} -QByteArray KQOAuthRequestPrivate::requestBaseString() { - QByteArray baseString; - - // Every request has these as the commont parameters. - baseString.append( oauthHttpMethodString.toUtf8() + "&"); // HTTP method - baseString.append( QUrl::toPercentEncoding( oauthRequestEndpoint.toString(QUrl::RemoveQuery) ) + "&" ); // The path and query components - - QList< QPair > baseStringParameters; - baseStringParameters.append(requestParameters); - baseStringParameters.append(additionalParameters); - - // Sort the request parameters. These parameters have been - // initialized earlier. - qSort(baseStringParameters.begin(), - baseStringParameters.end(), - normalizedParameterSort - ); - - // Last append the request parameters correctly encoded. - baseString.append( encodedParamaterList(baseStringParameters) ); - - if (debugOutput) { - qDebug() << "========== KQOAuthRequest has the following base string:"; - qDebug() << baseString << "\n"; - } - - return baseString; -} - -QByteArray KQOAuthRequestPrivate::encodedParamaterList(const QList< QPair > ¶meters) { - QByteArray resultList; - - bool first = true; - QPair parameter; - - // Do the debug output. - if (debugOutput) { - qDebug() << "========== KQOAuthRequest has the following parameters:"; - } - foreach (parameter, parameters) { - if(!first) { - resultList.append( "&" ); - } else { - first = false; - } - - // Here we don't need to explicitely encode the strings to UTF-8 since - // QUrl::toPercentEncoding() takes care of that for us. - resultList.append( QUrl::toPercentEncoding(parameter.first) // Parameter key - + "=" - + QUrl::toPercentEncoding(parameter.second) // Parameter value - ); - if (debugOutput) { - qDebug() << " * " - << parameter.first - << " : " - << parameter.second; - } - } - if (debugOutput) { - qDebug() << "\n"; - } - - return QUrl::toPercentEncoding(resultList); -} - -QString KQOAuthRequestPrivate::oauthTimestamp() const { - // This is basically for unit tests only. In most cases we don't set the nonce beforehand. - if (!oauthTimestamp_.isEmpty()) { - return oauthTimestamp_; - } - -#if QT_VERSION >= 0x040700 - return QString::number(QDateTime::currentDateTimeUtc().toTime_t()); -#else - return QString::number(QDateTime::currentDateTime().toUTC().toTime_t()); -#endif - -} - -QString KQOAuthRequestPrivate::oauthNonce() const { - // This is basically for unit tests only. In most cases we don't set the nonce beforehand. - return QString::number(qrand()); -} - -bool KQOAuthRequestPrivate::validateRequest() const { - switch ( requestType ) { - case KQOAuthRequest::TemporaryCredentials: - if (oauthRequestEndpoint.isEmpty() - || oauthConsumerKey.isEmpty() - || oauthNonce_.isEmpty() - || oauthSignatureMethod.isEmpty() - || oauthTimestamp_.isEmpty() - || oauthVersion.isEmpty()) - { - return false; - } - return true; - - case KQOAuthRequest::AccessToken: - if (oauthRequestEndpoint.isEmpty() - || oauthVerifier.isEmpty() - || oauthConsumerKey.isEmpty() - || oauthNonce_.isEmpty() - || oauthSignatureMethod.isEmpty() - || oauthTimestamp_.isEmpty() - || oauthToken.isEmpty() - || oauthTokenSecret.isEmpty() - || oauthVersion.isEmpty()) - { - return false; - } - return true; - - case KQOAuthRequest::AuthorizedRequest: - if(requestOAuthMethod == KQOAuthRequest::OAUTH1) { - if (oauthRequestEndpoint.isEmpty() - || oauthConsumerKey.isEmpty() - || oauthNonce_.isEmpty() - || oauthSignatureMethod.isEmpty() - || oauthTimestamp_.isEmpty() - || oauthToken.isEmpty() - || oauthTokenSecret.isEmpty() - || oauthVersion.isEmpty()) - { - return false; - } - return true; - } else { - if(oauthToken.isEmpty()){ - return false; - } - return true; - } - - default: - return false; - } - - // We should not come here. - return false; -} - -//////////// Public implementation //////////////// - -KQOAuthRequest::KQOAuthRequest(QObject *parent) : - QObject(parent), - d_ptr(new KQOAuthRequestPrivate) -{ - d_ptr->debugOutput = false; // No debug output by default. - qsrand(QTime::currentTime().msec()); // We need to seed the nonce random number with something. - // However, we cannot do this while generating the nonce since - // we might get the same seed. So initializing here should be fine. -} - -KQOAuthRequest::~KQOAuthRequest() -{ - delete d_ptr; -} - -void KQOAuthRequest::initRequest(KQOAuthRequest::RequestType type, const QUrl &requestEndpoint) { - Q_D(KQOAuthRequest); - - if (!requestEndpoint.isValid()) { - qWarning() << "Endpoint URL is not valid. Ignoring. This request might not work."; - return; - } - - if (type < 0 || type > KQOAuthRequest::AuthorizedRequest) { - qWarning() << "Invalid request type. Ignoring. This request might not work."; - return; - } - - // Clear the request - clearRequest(); - - // Set smart defaults. - d->requestType = type; - d->oauthRequestEndpoint = requestEndpoint; - d->oauthTimestamp_ = d->oauthTimestamp(); - d->oauthNonce_ = d->oauthNonce(); - this->setSignatureMethod(KQOAuthRequest::HMAC_SHA1); - this->setHttpMethod(KQOAuthRequest::POST); - this->setRequestOAuthMethod(KQOAuthRequest::OAUTH1); - d->oauthVersion = "1.0"; // Currently supports only version 1.0 - - d->contentType = "application/x-www-form-urlencoded"; -} - -void KQOAuthRequest::setConsumerKey(const QString &consumerKey) { - Q_D(KQOAuthRequest); - d->oauthConsumerKey = consumerKey; -} - -void KQOAuthRequest::setConsumerSecretKey(const QString &consumerSecretKey) { - Q_D(KQOAuthRequest); - d->oauthConsumerSecretKey = consumerSecretKey; -} - -void KQOAuthRequest::setCallbackUrl(const QUrl &callbackUrl) { - Q_D(KQOAuthRequest); - - d->oauthCallbackUrl = callbackUrl; -} - -void KQOAuthRequest::setSignatureMethod(KQOAuthRequest::RequestSignatureMethod requestMethod) { - Q_D(KQOAuthRequest); - QString requestMethodString; - - switch (requestMethod) { - case KQOAuthRequest::PLAINTEXT: - requestMethodString = "PLAINTEXT"; - break; - case KQOAuthRequest::HMAC_SHA1: - requestMethodString = "HMAC-SHA1"; - break; - case KQOAuthRequest::RSA_SHA1: - requestMethodString = "RSA-SHA1"; - break; - default: - // We should not come here - qWarning() << "Invalid signature method set."; - break; - } - - d->oauthSignatureMethod = requestMethodString; -} - -void KQOAuthRequest::setTokenSecret(const QString &tokenSecret) { - Q_D(KQOAuthRequest); - - d->oauthTokenSecret = tokenSecret; -} - -void KQOAuthRequest::setToken(const QString &token) { - Q_D(KQOAuthRequest); - - d->oauthToken = token; -} - -void KQOAuthRequest::setVerifier(const QString &verifier) { - Q_D(KQOAuthRequest); - - d->oauthVerifier = verifier; -} - - -void KQOAuthRequest::setHttpMethod(KQOAuthRequest::RequestHttpMethod httpMethod) { - Q_D(KQOAuthRequest); - - QString requestHttpMethodString; - - switch (httpMethod) { - case KQOAuthRequest::GET: - requestHttpMethodString = "GET"; - break; - case KQOAuthRequest::POST: - requestHttpMethodString = "POST"; - break; - default: - qWarning() << "Invalid HTTP method set."; - break; - } - - d->oauthHttpMethod = httpMethod; - d->oauthHttpMethodString = requestHttpMethodString; -} - -void KQOAuthRequest::setRequestOAuthMethod(KQOAuthRequest::RequestOAuthMethod oauthMethod) { - Q_D(KQOAuthRequest); - - d->requestOAuthMethod = oauthMethod; -} - -KQOAuthRequest::RequestHttpMethod KQOAuthRequest::httpMethod() const { - Q_D(const KQOAuthRequest); - - return d->oauthHttpMethod; -} - -KQOAuthRequest::RequestOAuthMethod KQOAuthRequest::oauthMethod() const { - Q_D(const KQOAuthRequest); - - return d->requestOAuthMethod; -} - -void KQOAuthRequest::setAdditionalParameters(const KQOAuthParameters &additionalParams) { - Q_D(KQOAuthRequest); - - QList additionalKeys = additionalParams.keys(); - QList additionalValues = additionalParams.values(); - - int i=0; - foreach(QString key, additionalKeys) { - QString value = additionalValues.at(i); - d->additionalParameters.append( qMakePair(key, value) ); - i++; - } -} - -KQOAuthParameters KQOAuthRequest::additionalParameters() const { - Q_D(const KQOAuthRequest); - - QMultiMap additionalParams; - for(int i=0; iadditionalParameters.size(); i++) { - additionalParams.insert(d->additionalParameters.at(i).first, - d->additionalParameters.at(i).second); - } - if(d->requestOAuthMethod == KQOAuthRequest::OAUTH2) { - additionalParams.insert(OAUTH_KEY_TOKEN, d->oauthToken); - } - - return additionalParams; -} - -KQOAuthRequest::RequestType KQOAuthRequest::requestType() const { - Q_D(const KQOAuthRequest); - return d->requestType; -} - -QUrl KQOAuthRequest::requestEndpoint() const { - Q_D(const KQOAuthRequest); - return d->oauthRequestEndpoint; -} - -QList KQOAuthRequest::requestParameters() { - Q_D(KQOAuthRequest); - - QList requestParamList; - - d->prepareRequest(); - if (!isValid() ) { - qWarning() << "Request is not valid! I will still sign it, but it will probably not work."; - } - if(d->requestOAuthMethod != KQOAuthRequest::OAUTH2) { - d->signRequest(); - } - - QPair requestParam; - QString param; - QString value; - foreach (requestParam, d->requestParameters) { - param = requestParam.first; - value = requestParam.second; - requestParamList.append(QString(param + "=\"" + value +"\"").toUtf8()); - } - - return requestParamList; -} - -QString KQOAuthRequest::contentType() -{ - Q_D(const KQOAuthRequest); - return d->contentType; -} - -void KQOAuthRequest::setContentType(const QString &contentType) -{ - Q_D(KQOAuthRequest); - d->contentType = contentType; -} - -QByteArray KQOAuthRequest::rawData() -{ - Q_D(const KQOAuthRequest); - return d->postRawData; -} - -void KQOAuthRequest::setRawData(const QByteArray &rawData) -{ - Q_D(KQOAuthRequest); - d->postRawData = rawData; -} - -QByteArray KQOAuthRequest::requestBody() const { - Q_D(const KQOAuthRequest); - - QByteArray postBodyContent; - bool first = true; - for(int i=0; i < d->additionalParameters.size(); i++) { - if(!first) { - postBodyContent.append("&"); - } else { - first = false; - } - - QString key = d->additionalParameters.at(i).first; - QString value = d->additionalParameters.at(i).second; - - postBodyContent.append(QUrl::toPercentEncoding(key) + QString("=").toUtf8() + - QUrl::toPercentEncoding(value)); - } - qDebug() << postBodyContent; - return postBodyContent; -} - -bool KQOAuthRequest::isValid() const { - Q_D(const KQOAuthRequest); - - return d->validateRequest(); -} - -void KQOAuthRequest::setTimeout(int timeoutMilliseconds) { - Q_D(KQOAuthRequest); - d->timeout = timeoutMilliseconds; -} - -void KQOAuthRequest::clearRequest() { - Q_D(KQOAuthRequest); - - d->oauthRequestEndpoint = ""; - d->oauthHttpMethodString = ""; - d->oauthConsumerKey = ""; - d->oauthConsumerSecretKey = ""; - d->oauthToken = ""; - d->oauthTokenSecret = ""; - d->oauthSignatureMethod = ""; - d->oauthCallbackUrl = ""; - d->oauthVerifier = ""; - d->oauthTimestamp_ = ""; - d->oauthNonce_ = ""; - d->requestParameters.clear(); - d->additionalParameters.clear(); - d->timeout = 0; -} - -void KQOAuthRequest::setEnableDebugOutput(bool enabled) { - Q_D(KQOAuthRequest); - d->debugOutput = enabled; -} - -/** - * Protected implementations for inherited classes - */ -bool KQOAuthRequest::validateXAuthRequest() const { - Q_D(const KQOAuthRequest); - - if (d->oauthRequestEndpoint.isEmpty() - || d->oauthConsumerKey.isEmpty() - || d->oauthNonce_.isEmpty() - || d->oauthSignatureMethod.isEmpty() - || d->oauthTimestamp_.isEmpty() - || d->oauthVersion.isEmpty()) - { - return false; - } - return true; -} - -bool KQOAuthRequest::validateOauth2Request() const { - Q_D(const KQOAuthRequest); - - if (d->oauthRequestEndpoint.isEmpty() || d->oauthToken.isEmpty()) - { - return false; - } - return true; -} - - -/** - * Private implementations for friend classes - */ -QString KQOAuthRequest::consumerKeyForManager() const { - Q_D(const KQOAuthRequest); - return d->oauthConsumerKey; -} - -QString KQOAuthRequest::consumerKeySecretForManager() const { - Q_D(const KQOAuthRequest); - return d->oauthConsumerSecretKey; -} - -QUrl KQOAuthRequest::callbackUrlForManager() const { - Q_D(const KQOAuthRequest); - return d->oauthCallbackUrl; -} - -void KQOAuthRequest::requestTimerStart() -{ - Q_D(KQOAuthRequest); - if (d->timeout > 0) { - connect(&(d->timer), SIGNAL(timeout()), this, SIGNAL(requestTimedout())); - d->timer.start(d->timeout); - } -} - -void KQOAuthRequest::requestTimerStop() -{ - Q_D(KQOAuthRequest); - if (d->timeout > 0) { - disconnect(&(d->timer), SIGNAL(timeout()), this, SIGNAL(requestTimedout())); - d->timer.stop(); - } -} diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest.h deleted file mode 100644 index 616003db73..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest.h +++ /dev/null @@ -1,157 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see - */ -#ifndef KQOAUTHREQUEST_H -#define KQOAUTHREQUEST_H - -#include -#include -#include - -#include "kqoauthglobals.h" - -typedef QMultiMap KQOAuthParameters; - -class KQOAuthRequestPrivate; -class KQOAUTH_EXPORT KQOAuthRequest : public QObject -{ - Q_OBJECT -public: - explicit KQOAuthRequest(QObject *parent = 0); - ~KQOAuthRequest(); - - enum RequestType { - TemporaryCredentials = 0, - AccessToken, - AuthorizedRequest - }; - - enum RequestSignatureMethod { - PLAINTEXT = 0, - HMAC_SHA1, - RSA_SHA1 - }; - - enum RequestHttpMethod { - GET = 0, - POST - }; - - enum RequestOAuthMethod { - OAUTH1 = 0, - OAUTH2 - }; - - /** - * These methods can be overridden in child classes which are different types of - * OAuth requests. - */ - // Validate the request of this type. - virtual bool isValid() const; - - /** - * These methods are OAuth request type specific and not overridden in child - * classes. - * NOTE: Refactorting still a TODO - */ - // Initialize the request of this type. - virtual void initRequest(KQOAuthRequest::RequestType type, const QUrl &requestEndpoint); - - void setConsumerKey(const QString &consumerKey); - void setConsumerSecretKey(const QString &consumerSecretKey); - - // Mandatory methods for acquiring a request token - void setCallbackUrl(const QUrl &callbackUrl); - - // Mandator methods for acquiring a access token - void setTokenSecret(const QString &tokenSecret); - void setToken(const QString &token); - void setVerifier(const QString &verifier); - - // Request signature method to use - HMAC_SHA1 currently only supported - void setSignatureMethod(KQOAuthRequest::RequestSignatureMethod = KQOAuthRequest::HMAC_SHA1); - - // Request's HTTP method. - void setHttpMethod(KQOAuthRequest::RequestHttpMethod = KQOAuthRequest::POST); - KQOAuthRequest::RequestHttpMethod httpMethod() const; - KQOAuthRequest::RequestOAuthMethod oauthMethod() const; - void setRequestOAuthMethod(KQOAuthRequest::RequestOAuthMethod = KQOAuthRequest::OAUTH1); - - // Sets the timeout for this request. If the timeout expires, signal "requestTimedout" will be - // emitted from the manager. - // 0 = If set to zero, timeout is disabled. - // TODO: Do we need some request ID now? - void setTimeout(int timeoutMilliseconds); - - // Additional optional parameters to the request. - void setAdditionalParameters(const KQOAuthParameters &additionalParams); - KQOAuthParameters additionalParameters() const; - QList requestParameters(); // This will return all request's parameters in the raw format given - // to the QNetworkRequest. - QByteArray requestBody() const; // This will return the POST body as given to the QNetworkRequest. - - KQOAuthRequest::RequestType requestType() const; - QUrl requestEndpoint() const; - - void setContentType(const QString &contentType); - QString contentType(); - - void setRawData(const QByteArray &rawData); - QByteArray rawData(); - - void clearRequest(); - - // Enable verbose debug output for request content. - void setEnableDebugOutput(bool enabled); - -Q_SIGNALS: - // This signal is emited if the request is not completed before the request's timeout - // value has expired. - void requestTimedout(); - -protected: - bool validateXAuthRequest() const; - bool validateOauth2Request() const; - -private: - KQOAuthRequestPrivate * const d_ptr; - Q_DECLARE_PRIVATE(KQOAuthRequest); - Q_DISABLE_COPY(KQOAuthRequest); - - // These classes are only for the internal use of KQOAuthManager so it can - // work with the opaque request. - QString consumerKeyForManager() const; - QString consumerKeySecretForManager() const; - QUrl callbackUrlForManager() const; - - // This method is for timeout handling by the KQOAuthManager. - void requestTimerStart(); - void requestTimerStop(); - - friend class KQOAuthManager; -#ifdef UNIT_TEST - friend class Ut_KQOAuth; -#endif -}; - -#endif // KQOAUTHREQUEST_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_1.cpp b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_1.cpp deleted file mode 100644 index 165eb3c23d..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_1.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "kqoauthrequest_1.h" - -KQOAuthRequest_1::KQOAuthRequest_1() -{ -} diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_1.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_1.h deleted file mode 100644 index 8da5df8f4b..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_1.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef KQOAUTHREQUEST_1_H -#define KQOAUTHREQUEST_1_H - -#include "kqoauthrequest.h" - -class KQOAUTH_EXPORT KQOAuthRequest_1 : public KQOAuthRequest -{ -public: - KQOAuthRequest_1(); -}; - -#endif // KQOAUTHREQUEST_1_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_p.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_p.h deleted file mode 100644 index 22be4ef7eb..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_p.h +++ /dev/null @@ -1,98 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see - */ -#ifndef KQOAUTHREQUEST_P_H -#define KQOAUTHREQUEST_P_H -#include "kqoauthglobals.h" -#include "kqoauthrequest.h" - -#include -#include -#include -#include -#include -#include - -class KQOAUTH_EXPORT KQOAuthRequestPrivate { - -public: - KQOAuthRequestPrivate(); - ~KQOAuthRequestPrivate(); - - // Helper methods to get the values for the OAuth request parameters. - QString oauthTimestamp() const; - QString oauthNonce() const; - QString oauthSignature(); - - // Utility methods for making the request happen. - void prepareRequest(); - void signRequest(); - bool validateRequest() const; - QByteArray requestBaseString(); - QByteArray encodedParamaterList(const QList< QPair > &requestParameters); - void insertAdditionalParams(); - void insertPostBody(); - - QUrl oauthRequestEndpoint; - KQOAuthRequest::RequestHttpMethod oauthHttpMethod; - QString oauthHttpMethodString; - QString oauthConsumerKey; - QString oauthConsumerSecretKey; - QString oauthToken; - QString oauthTokenSecret; - QString oauthSignatureMethod; - QUrl oauthCallbackUrl; - QString oauthVersion; - QString oauthVerifier; - - // These will be generated by the helper methods - QString oauthTimestamp_; - QString oauthNonce_; - - // User specified additional parameters needed for the request. - QList< QPair > additionalParameters; - - // The raw POST body content as given to the HTTP request. - QByteArray postBodyContent; - - // Protocol parameters. - // These parameters are used in the "Authorized" header of the HTTP request. - QList< QPair > requestParameters; - - KQOAuthRequest::RequestType requestType; - KQOAuthRequest::RequestOAuthMethod requestOAuthMethod; - - //The Content-Type HTTP header - QString contentType; - - //Raw data to post if type is not url-encoded - QByteArray postRawData; - - // Timeout for this request in milliseconds. - int timeout; - QTimer timer; - - bool debugOutput; - -}; -#endif // KQOAUTHREQUEST_P_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth.cpp b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth.cpp deleted file mode 100644 index 9f6a8593da..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see - */ -#include - -#include "kqoauthrequest_xauth_p.h" -#include "kqoauthrequest_xauth.h" - -/** - * Private d_ptr implementations. - */ -KQOAuthRequest_XAuthPrivate::KQOAuthRequest_XAuthPrivate() -{ - -} - -KQOAuthRequest_XAuthPrivate::~KQOAuthRequest_XAuthPrivate() -{ -} - -/** - * Public implementations. - */ -KQOAuthRequest_XAuth::KQOAuthRequest_XAuth(QObject *parent) : - KQOAuthRequest(parent), - d_ptr(new KQOAuthRequest_XAuthPrivate) -{ -} - -bool KQOAuthRequest_XAuth::isValid() const { - // An xAuth can never request temporary credentials. - if (requestType() == KQOAuthRequest::TemporaryCredentials) { - qWarning() << "XAuth request cannot be of type KQOAuthRequest::TemporaryCredentials. Aborting."; - return false; - } - - // Access token must always be retrieved using the POST HTTP method. - if (requestType() == KQOAuthRequest::AccessToken - && httpMethod() != KQOAuthRequest::POST) { - - qWarning() << "Access tokens must be fetched using the POST HTTP method. Aborting."; - - return false; - } - - if (!xauth_parameters_set) { - qWarning() << "No XAuth parameters set. Aborting."; - return false; - } - - // And then check the validity of the XAuth request. - // Provided by the base class as a protected method for us. - return validateXAuthRequest(); -} - -void KQOAuthRequest_XAuth::setXAuthLogin(const QString &username, - const QString &password) { - - if (username.isEmpty() || password.isEmpty()) { - qWarning() << "Username or password cannot be empty. Aborting."; - return; - } - - xauth_parameters_set = true; - - qDebug() << username << password; - - KQOAuthParameters xauthParams; - xauthParams.insert("x_auth_username", username); - xauthParams.insert("x_auth_password", password); - xauthParams.insert("x_auth_mode", "client_auth"); - - setAdditionalParameters(xauthParams); -} - diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth.h deleted file mode 100644 index 93539cb785..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth.h +++ /dev/null @@ -1,53 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see - */ -#ifndef KQOAUTHREQUEST_XAUTH_H -#define KQOAUTHREQUEST_XAUTH_H - -#include "kqoauthrequest.h" -#include "kqoauthrequest_1.h" - -class KQOAuthRequest_XAuthPrivate; -class KQOAUTH_EXPORT KQOAuthRequest_XAuth : public KQOAuthRequest -{ - Q_OBJECT -public: - KQOAuthRequest_XAuth(QObject *parent = 0); - - /** - * These methods can be overridden in child classes which are different types of - * OAuth requests. - */ - // Validate the request of this type. - bool isValid() const; - - // Give the xAuth specific parameters. - void setXAuthLogin(const QString &username = "", - const QString &password = ""); - -private: - KQOAuthRequest_XAuthPrivate * const d_ptr; - bool xauth_parameters_set; -}; - -#endif // KQOAUTHREQUEST_XAUTH_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth_p.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth_p.h deleted file mode 100644 index 9f79d31ef8..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth_p.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef KQOAUTHREQUEST_XAUTH_P_H -#define KQOAUTHREQUEST_XAUTH_P_H - -#include "kqoauthglobals.h" - -class KQOAuthRequest; -class KQOAUTH_EXPORT KQOAuthRequest_XAuthPrivate -{ -public: - KQOAuthRequest_XAuthPrivate(); - ~KQOAuthRequest_XAuthPrivate(); -}; - -#endif // KQOAUTHREQUEST_XAUTH_P_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthutils.cpp b/src/libtomahawk/thirdparty/kqoauth/kqoauthutils.cpp deleted file mode 100644 index d021385ef8..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthutils.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see - */ -#include -#include -#include - -#include -#include "kqoauthutils.h" - -QString KQOAuthUtils::hmac_sha1(const QString &message, const QString &key) -{ - QByteArray keyBytes = key.toAscii(); - int keyLength; // Lenght of key word - const int blockSize = 64; // Both MD5 and SHA-1 have a block size of 64. - - keyLength = keyBytes.size(); - // If key is longer than block size, we need to hash the key - if (keyLength > blockSize) { - QCryptographicHash hash(QCryptographicHash::Sha1); - hash.addData(keyBytes); - keyBytes = hash.result(); - } - - /* http://tools.ietf.org/html/rfc2104 - (1) */ - // Create the opad and ipad for the hash function. - QByteArray ipad; - QByteArray opad; - - ipad.fill( 0, blockSize); - opad.fill( 0, blockSize); - - ipad.replace(0, keyBytes.length(), keyBytes); - opad.replace(0, keyBytes.length(), keyBytes); - - /* http://tools.ietf.org/html/rfc2104 - (2) & (5) */ - for (int i=0; i<64; i++) { - ipad[i] = ipad[i] ^ 0x36; - opad[i] = opad[i] ^ 0x5c; - } - - QByteArray workArray; - workArray.clear(); - - workArray.append(ipad, 64); - /* http://tools.ietf.org/html/rfc2104 - (3) */ - workArray.append(message.toAscii()); - - - /* http://tools.ietf.org/html/rfc2104 - (4) */ - QByteArray sha1 = QCryptographicHash::hash(workArray, QCryptographicHash::Sha1); - - /* http://tools.ietf.org/html/rfc2104 - (6) */ - workArray.clear(); - workArray.append(opad, 64); - workArray.append(sha1); - - sha1.clear(); - - /* http://tools.ietf.org/html/rfc2104 - (7) */ - sha1 = QCryptographicHash::hash(workArray, QCryptographicHash::Sha1); - return QString(sha1.toBase64()); -} diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthutils.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthutils.h deleted file mode 100644 index db1f8840fd..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthutils.h +++ /dev/null @@ -1,37 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see - */ -#ifndef KQOAUTHUTILS_H -#define KQOAUTHUTILS_H - -#include "kqoauthglobals.h" - -class QString; -class KQOAUTH_EXPORT KQOAuthUtils -{ -public: - - static QString hmac_sha1(const QString &message, const QString &key); -}; - -#endif // KQOAUTHUTILS_H From 3b4efbad6d42f79934e0557218b4759cbd346b0c Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Fri, 22 Mar 2013 08:43:38 +0100 Subject: [PATCH 26/76] Add licence and source for Tomahawk.bind Style correction. --- data/js/tomahawk.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/data/js/tomahawk.js b/data/js/tomahawk.js index 951c461128..64b10141ba 100644 --- a/data/js/tomahawk.js +++ b/data/js/tomahawk.js @@ -235,9 +235,9 @@ Tomahawk.syncRequest = function(url, extraHeaders) } xmlHttpRequest.send(null); - if (xmlHttpRequest.status == 200){ + if (xmlHttpRequest.status == 200) { return xmlHttpRequest.responseText; - }else if (xmlHttpRequest.readyState === 4) { + } else if (xmlHttpRequest.readyState === 4) { Tomahawk.log("Failed to do Get request: to: " + url); Tomahawk.log("Status Code was: " + xmlHttpRequest.status); } @@ -449,6 +449,11 @@ Tomahawk.sha256=function(s){ }; +/* + * Bind the function to be executed in the scope of the object oThis. + * Any copyright is dedicated to the Public Domain. + * Source : http://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind#Compatibility + */ if (!Function.prototype.bind) { Function.prototype.bind = function (oThis) { if (typeof this !== "function") { From f3990bd9f60267fe0d039713ce39640690445687 Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Fri, 22 Mar 2013 10:33:24 +0100 Subject: [PATCH 27/76] Remove dropbox icon from Tomahawk. --- resources.qrc | 1 - src/libtomahawk/utils/TomahawkUtilsGui.cpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/resources.qrc b/resources.qrc index 9e19cb6836..f22787eab5 100644 --- a/resources.qrc +++ b/resources.qrc @@ -149,7 +149,6 @@ data/images/ok.svg data/images/tweet.svg data/images/widget-border.png - data/images/dropbox-icon.png data/images/refresh.svg diff --git a/src/libtomahawk/utils/TomahawkUtilsGui.cpp b/src/libtomahawk/utils/TomahawkUtilsGui.cpp index ef19cfc8d3..f61c343861 100644 --- a/src/libtomahawk/utils/TomahawkUtilsGui.cpp +++ b/src/libtomahawk/utils/TomahawkUtilsGui.cpp @@ -705,7 +705,7 @@ defaultPixmap( ImageType type, ImageMode mode, const QSize& size ) pixmap = ImageRegistry::instance()->pixmap( RESPATH "images/spotify-sourceicon.svg", size ); break; case DropboxIcon: - pixmap = ImageRegistry::instance()->pixmap( RESPATH "images/dropbox-icon.png", size ); + pixmap = ImageRegistry::instance()->pixmap( RESPATH "images/dropbox-icon.svg", size ); break; case SoundcloudIcon: pixmap = ImageRegistry::instance()->pixmap( RESPATH "images/soundcloud.svg", size ); From 5ce025fb5cec5288a978a566df9d4e4e145fd3cf Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Fri, 22 Mar 2013 11:06:27 +0100 Subject: [PATCH 28/76] Finish deleting of dropbox incon in tomahawk. --- src/libtomahawk/utils/TomahawkUtils.h | 1 - src/libtomahawk/utils/TomahawkUtilsGui.cpp | 3 --- 2 files changed, 4 deletions(-) diff --git a/src/libtomahawk/utils/TomahawkUtils.h b/src/libtomahawk/utils/TomahawkUtils.h index 3546777105..a245952ef1 100644 --- a/src/libtomahawk/utils/TomahawkUtils.h +++ b/src/libtomahawk/utils/TomahawkUtils.h @@ -113,7 +113,6 @@ namespace TomahawkUtils DropTopSongs, LastfmIcon, SpotifyIcon, - DropboxIcon, SoundcloudIcon, AccountNone, Starred, diff --git a/src/libtomahawk/utils/TomahawkUtilsGui.cpp b/src/libtomahawk/utils/TomahawkUtilsGui.cpp index f61c343861..247be38ebb 100644 --- a/src/libtomahawk/utils/TomahawkUtilsGui.cpp +++ b/src/libtomahawk/utils/TomahawkUtilsGui.cpp @@ -704,9 +704,6 @@ defaultPixmap( ImageType type, ImageMode mode, const QSize& size ) case SpotifyIcon: pixmap = ImageRegistry::instance()->pixmap( RESPATH "images/spotify-sourceicon.svg", size ); break; - case DropboxIcon: - pixmap = ImageRegistry::instance()->pixmap( RESPATH "images/dropbox-icon.svg", size ); - break; case SoundcloudIcon: pixmap = ImageRegistry::instance()->pixmap( RESPATH "images/soundcloud.svg", size ); break; From dce4a27b1e7db9181d60483e87ba65d83c562cd8 Mon Sep 17 00:00:00 2001 From: loclamor Date: Mon, 25 Mar 2013 13:07:16 +0100 Subject: [PATCH 29/76] update of cloudstreaming to ask a new streamUrl on HTTP error --- .../resolvers/QtScriptResolver.cpp | 8 +-- src/libtomahawk/resolvers/QtScriptResolver.h | 4 +- src/libtomahawk/utils/cloudstream.cpp | 60 +++++++++++++++---- src/libtomahawk/utils/cloudstream.h | 20 +++++-- 4 files changed, 70 insertions(+), 22 deletions(-) diff --git a/src/libtomahawk/resolvers/QtScriptResolver.cpp b/src/libtomahawk/resolvers/QtScriptResolver.cpp index 79fc62b958..d87e548b2d 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.cpp +++ b/src/libtomahawk/resolvers/QtScriptResolver.cpp @@ -356,7 +356,7 @@ QtScriptResolverHelper::base64Decode( const QByteArray& input ) void -QtScriptResolverHelper::ReadCloudFile(const QString& fileName, const QString& fileId, const QString& sizeS, const QString& mime_type, const QVariant& requestJS, const QString& javascriptCallbackFunction) +QtScriptResolverHelper::ReadCloudFile(const QString& fileName, const QString& fileId, const QString& sizeS, const QString& mime_type, const QVariant& requestJS, const QString& javascriptCallbackFunction, const QString& javascriptRefreshUrlFunction) { QVariantMap request; @@ -389,7 +389,7 @@ QtScriptResolverHelper::ReadCloudFile(const QString& fileName, const QString& fi CloudStream* stream = new CloudStream( - download_url, fileName, size, headers, network); + download_url, fileName, fileId, size, headers, network, m_resolver, javascriptRefreshUrlFunction); stream->Precache(); boost::scoped_ptr tag; if (mime_type == "audio/mpeg") { // && title.endsWith(".mp3")) { @@ -1299,8 +1299,8 @@ QtScriptResolver::resolverCollections() // + data. } -void QtScriptResolver::executeJavascript(const QString &js) +QVariant QtScriptResolver::executeJavascript(const QString &js) { - m_engine->mainFrame()->evaluateJavaScript( RESOLVER_LEGACY_CODE + js ); + return m_engine->mainFrame()->evaluateJavaScript( RESOLVER_LEGACY_CODE + js ); } diff --git a/src/libtomahawk/resolvers/QtScriptResolver.h b/src/libtomahawk/resolvers/QtScriptResolver.h index b8a358881c..716a63d5de 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.h +++ b/src/libtomahawk/resolvers/QtScriptResolver.h @@ -67,7 +67,7 @@ Q_OBJECT // send ID3Tags of the stream as argument of the callback function Q_INVOKABLE void - ReadCloudFile(const QString& fileName, const QString& fileId, const QString& sizeS, const QString& mime_type, const QVariant& requestJS, const QString& javascriptCallbackFunction); + ReadCloudFile(const QString& fileName, const QString& fileId, const QString& sizeS, const QString& mime_type, const QVariant& requestJS, const QString& javascriptCallbackFunction, const QString& javascriptRefreshUrlFunction); Q_INVOKABLE void addLocalJSFile(const QString& jsFilePath); @@ -195,7 +195,7 @@ public slots: virtual void albums( const Tomahawk::collection_ptr& collection, const Tomahawk::artist_ptr& artist ); virtual void tracks( const Tomahawk::collection_ptr& collection, const Tomahawk::album_ptr& album ); - void executeJavascript(const QString& ); + QVariant executeJavascript(const QString& ); signals: void stopped(); diff --git a/src/libtomahawk/utils/cloudstream.cpp b/src/libtomahawk/utils/cloudstream.cpp index b2956233a1..5dafaeb91e 100644 --- a/src/libtomahawk/utils/cloudstream.cpp +++ b/src/libtomahawk/utils/cloudstream.cpp @@ -29,25 +29,32 @@ #include "utils/Logger.h" - +#include "resolvers/QtScriptResolver.h" namespace { static const int kTaglibPrefixCacheBytes = 64 * 1024; // Should be enough. static const int kTaglibSuffixCacheBytes = 8 * 1024; } +const static int MAX_ALLOW_ERROR_QUERY = 2; + CloudStream::CloudStream( - const QUrl& url, const QString& filename, const long length, - const QVariantMap& headers, QNetworkAccessManager* network) + QUrl& url, const QString& filename, const QString& fileId, const long length, + QVariantMap& headers, QNetworkAccessManager* network, QtScriptResolver* scriptResolver, + const QString & javascriptRefreshUrlFunction) : url_(url), filename_(filename), + fileId_(fileId), encoded_filename_(filename_.toUtf8()), length_(length), headers_(headers), cursor_(0), network_(network), cache_(length), - num_requests_(0) { + num_requests_(0), + num_requests_in_error_(0), + scriptResolver_(scriptResolver), + javascriptRefreshUrlFunction_(javascriptRefreshUrlFunction) { tDebug( LOGINFO ) << "#### Cloudstream : CloudStream object created for " << filename_ << " : " << url_.toString(); } @@ -117,7 +124,7 @@ TagLib::ByteVector CloudStream::readBlock(ulong length) { cursor_ += cached.size(); return cached; } - +/* QString authorizationHeader = headers_["Authorization"].toString(); QStringList authorizations = authorizationHeader.split(","); QStringList oneAuthList; @@ -145,14 +152,14 @@ TagLib::ByteVector CloudStream::readBlock(ulong length) { } } - QMap newHeaders = headers_; + //QMap newHeaders = headers_; newHeaders.insert("Authorization", QVariant(newAuthorizationHeader.join(", "))); - +*/ QNetworkRequest request = QNetworkRequest(url_); //setings of specials OAuth (1 or 2) headers - foreach(const QString& headerName, newHeaders.keys()) { - request.setRawHeader(headerName.toLocal8Bit(), newHeaders[headerName].toString().toLocal8Bit()); + foreach(const QString& headerName, headers_.keys()) { + request.setRawHeader(headerName.toLocal8Bit(), headers_[headerName].toString().toLocal8Bit()); } @@ -188,9 +195,40 @@ TagLib::ByteVector CloudStream::readBlock(ulong length) { tDebug( LOGINFO ) << "#### Cloudstream : header reply " << pair; } - if (code >= 400) { + if (code != 206) { + num_requests_in_error_++; tDebug( LOGINFO ) << "#### Cloudstream : Error " << code << " retrieving url to tag for " << filename_; - return TagLib::ByteVector(); + if(num_requests_in_error_ <= MAX_ALLOW_ERROR_QUERY and !javascriptRefreshUrlFunction_.isEmpty()){ + tDebug( LOGINFO ) << "####### Cloudstream : trying to get a good URL for " << fileId_; + QString refreshUrl = QString("resolver.%1( \"%2\" );").arg( javascriptRefreshUrlFunction_ ) + .arg( fileId_ ); + tDebug( LOGINFO ) << refreshUrl; + QVariant response = scriptResolver_->executeJavascript(refreshUrl); + QVariantMap request; + if(response.type() == QVariant::Map) + { + request = response.toMap(); + + url_ = QUrl(request["url"].toString()); + + headers_ = request["headers"].toMap(); + } + else + { + url_ = QUrl(response.toString()); + } + + TagLib::ByteVector bytes = readBlock(length); + //if we have datas, let another chance to parse ID3Tags (especially for Dropbox) + if(bytes.size() > 0){ + tDebug( LOGINFO ) << "#### Cloudstream : we have a response !"; + num_requests_in_error_--; + } + return bytes; + } + else { + return TagLib::ByteVector(); + } } QByteArray data = reply->readAll(); diff --git a/src/libtomahawk/utils/cloudstream.h b/src/libtomahawk/utils/cloudstream.h index 8f0f9d5282..89725ea5c0 100644 --- a/src/libtomahawk/utils/cloudstream.h +++ b/src/libtomahawk/utils/cloudstream.h @@ -28,15 +28,17 @@ #include class QNetworkAccessManager; +class QtScriptResolver; class CloudStream : public QObject, public TagLib::IOStream { Q_OBJECT public: - CloudStream(const QUrl& url, + CloudStream(QUrl& url, const QString& filename, + const QString& fileId, const long length, - const QVariantMap& headers, - QNetworkAccessManager* network); + QVariantMap& headers, + QNetworkAccessManager* network, QtScriptResolver *scriptResolver, const QString& javascriptRefreshUrlFunction); //Taglib::IOStream; virtual TagLib::FileName name() const; @@ -60,6 +62,10 @@ class CloudStream : public QObject, public TagLib::IOStream { return num_requests_; } + int num_requests_in_error() const { + return num_requests_in_error_; + } + // Use educated guess to request the bytes that TagLib will probably want. void Precache(); @@ -72,17 +78,21 @@ class CloudStream : public QObject, public TagLib::IOStream { void SSLErrors(const QList& errors); private: - const QUrl url_; + QUrl url_; const QString filename_; + const QString fileId_; const QByteArray encoded_filename_; const ulong length_; - const QVariantMap headers_; + QVariantMap headers_; + const QString javascriptRefreshUrlFunction_; int cursor_; QNetworkAccessManager* network_; + QtScriptResolver* scriptResolver_; google::sparsetable cache_; int num_requests_; + int num_requests_in_error_; }; //#endif // GOOGLEDRIVESTREAM_H From 7e320eac51c5a54a0ad4d562817a282b37fa23a3 Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Mon, 25 Mar 2013 15:35:19 +0100 Subject: [PATCH 30/76] Add developersExtras when executing JS resolver. Allow the display of the QWebInspector. --- src/libtomahawk/resolvers/QtScriptResolver.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libtomahawk/resolvers/QtScriptResolver.h b/src/libtomahawk/resolvers/QtScriptResolver.h index 716a63d5de..cc824abf21 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.h +++ b/src/libtomahawk/resolvers/QtScriptResolver.h @@ -122,6 +122,7 @@ Q_OBJECT settings()->setAttribute( QWebSettings::LocalStorageDatabaseEnabled, true ); settings()->setAttribute( QWebSettings::LocalContentCanAccessFileUrls, true ); settings()->setAttribute( QWebSettings::LocalContentCanAccessRemoteUrls, true ); + settings()->setAttribute( QWebSettings::DeveloperExtrasEnabled, true ); // Tomahawk is not a user agent m_header = QWebPage::userAgentForUrl( QUrl() ).replace( QString( "%1/%2" ) From 6e60cc6444e6a6f7744fe82c5871d6425b064df3 Mon Sep 17 00:00:00 2001 From: loclamor Date: Mon, 25 Mar 2013 15:50:45 +0100 Subject: [PATCH 31/76] use of qjson to encode the json generate by readCloudFile --- .../resolvers/QtScriptResolver.cpp | 25 ++++------- src/libtomahawk/utils/cloudstream.cpp | 42 +++++-------------- 2 files changed, 20 insertions(+), 47 deletions(-) diff --git a/src/libtomahawk/resolvers/QtScriptResolver.cpp b/src/libtomahawk/resolvers/QtScriptResolver.cpp index d87e548b2d..37bf6964be 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.cpp +++ b/src/libtomahawk/resolvers/QtScriptResolver.cpp @@ -86,6 +86,8 @@ #include #include + +#include "qjson/serializer.h" //--- end includes readcloudfile // FIXME: bloody hack, remove this for 0.3 @@ -372,13 +374,13 @@ QtScriptResolverHelper::ReadCloudFile(const QString& fileName, const QString& fi { request = requestJS.toMap(); - download_url = QUrl(request["url"].toString()); + download_url = QUrl::fromUserInput(request["url"].toString()); headers = request["headers"].toMap(); } else { - download_url = QUrl(requestJS.toString()); + download_url = QUrl::fromUserInput(requestJS.toString()); } tDebug( LOGINFO ) << "#### ReadCloudFile : Loading tags of " << fileName << " from " << download_url.toString() << " which have id " << fileId; @@ -474,23 +476,14 @@ QtScriptResolverHelper::ReadCloudFile(const QString& fileName, const QString& fi */ } - QString tabTagsJSON = "{"; - //we convert the QVariantMap to JSON to give it as an argument of the callback function - int nbTags = m.count(); - int i = 1; - foreach(const QString& tag, m.keys()) { - tabTagsJSON += "'" + tag + "' : '" + m[tag].toString() + "'"; - if(i != nbTags){ - tabTagsJSON += ", "; - } - i++; - } - tabTagsJSON += "}"; + QJson::Serializer serializer; + + QByteArray json = serializer.serialize(m); - tDebug() << "#### ReadCloudFile : Sending tags to js : " <m_engine->mainFrame()->evaluateJavaScript( getUrl ); } diff --git a/src/libtomahawk/utils/cloudstream.cpp b/src/libtomahawk/utils/cloudstream.cpp index 5dafaeb91e..b6da2c512d 100644 --- a/src/libtomahawk/utils/cloudstream.cpp +++ b/src/libtomahawk/utils/cloudstream.cpp @@ -119,42 +119,16 @@ TagLib::ByteVector CloudStream::readBlock(ulong length) { return TagLib::ByteVector(); } + if(num_requests_in_error_ > MAX_ALLOW_ERROR_QUERY){ + return TagLib::ByteVector(); + } + if (CheckCache(start, end)) { TagLib::ByteVector cached = GetCached(start, end); cursor_ += cached.size(); return cached; } -/* - QString authorizationHeader = headers_["Authorization"].toString(); - QStringList authorizations = authorizationHeader.split(","); - QStringList oneAuthList; - QStringList newAuthorizationHeader; - foreach(const QString& oneAuth, authorizations){ - if(oneAuth.contains("oauth_nonce")){ - oneAuthList = oneAuth.split("="); - tDebug() << "######## CloudStream : oauth_nonce : " << oneAuthList[1]; - QString oauthNonce = oneAuthList[1].replace('"',""); - - tDebug() << "######## CloudStream : oauth_nonce : " << oauthNonce; //ok - - int newOautNonce = oauthNonce.toInt(0,16); - tDebug() << "######## CloudStream : oauth_nonce : " << newOautNonce; // =0 !!! - newOautNonce++; - tDebug() << "######## CloudStream : NEW oauth_nonce : " << newOautNonce; - - oauthNonce = QString::number(newOautNonce,16).toUpper(); - - newAuthorizationHeader.append(oneAuthList[0]+"=\""+oauthNonce+"\""); - } - else { - newAuthorizationHeader.append(oneAuth); - } - } - - //QMap newHeaders = headers_; - newHeaders.insert("Authorization", QVariant(newAuthorizationHeader.join(", "))); -*/ QNetworkRequest request = QNetworkRequest(url_); //setings of specials OAuth (1 or 2) headers @@ -198,12 +172,18 @@ TagLib::ByteVector CloudStream::readBlock(ulong length) { if (code != 206) { num_requests_in_error_++; tDebug( LOGINFO ) << "#### Cloudstream : Error " << code << " retrieving url to tag for " << filename_; - if(num_requests_in_error_ <= MAX_ALLOW_ERROR_QUERY and !javascriptRefreshUrlFunction_.isEmpty()){ + if(!javascriptRefreshUrlFunction_.isEmpty()){ tDebug( LOGINFO ) << "####### Cloudstream : trying to get a good URL for " << fileId_; QString refreshUrl = QString("resolver.%1( \"%2\" );").arg( javascriptRefreshUrlFunction_ ) .arg( fileId_ ); tDebug( LOGINFO ) << refreshUrl; QVariant response = scriptResolver_->executeJavascript(refreshUrl); + + + if(response.isNull()){ + tDebug( LOGINFO ) << "####### Cloudstream : response is empty, returning" << response; + return TagLib::ByteVector(); + } QVariantMap request; if(response.type() == QVariant::Map) { From 8335844fd8aba5ecd7486014d3ef438485b32d27 Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Wed, 27 Mar 2013 19:00:04 +0100 Subject: [PATCH 32/76] Repair mistak in customIODeviceFactory. --- src/libtomahawk/resolvers/QtScriptResolver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/resolvers/QtScriptResolver.cpp b/src/libtomahawk/resolvers/QtScriptResolver.cpp index 37bf6964be..84cba51e96 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.cpp +++ b/src/libtomahawk/resolvers/QtScriptResolver.cpp @@ -526,7 +526,7 @@ QtScriptResolverHelper::customIODeviceFactory( const Tomahawk::result_ptr& resul QString getUrl = QString( "Tomahawk.resolver.instance.%1( '%2' );" ).arg( m_urlCallback ) .arg( QString( QUrl( result->url() ).toEncoded() ) ); - QVariant jsResult = m_resolver->m_engine->mainFrame()->evaluateJavaScript( getUrl ).toString(); + QVariant jsResult = m_resolver->m_engine->mainFrame()->evaluateJavaScript( getUrl ); if(jsResult.type() == QVariant::Map) { From b74d1df9d5664146879af750c5ca8d3aa51fd4b9 Mon Sep 17 00:00:00 2001 From: loclamor Date: Wed, 27 Mar 2013 20:39:28 +0100 Subject: [PATCH 33/76] add a refreshUrlEachTime parameter to cloudstream and readCloudStream ; separate the refresh url code in a dedicated function --- .../resolvers/QtScriptResolver.cpp | 20 ++-- src/libtomahawk/resolvers/QtScriptResolver.h | 4 +- src/libtomahawk/utils/cloudstream.cpp | 110 +++++++++++------- src/libtomahawk/utils/cloudstream.h | 9 +- 4 files changed, 90 insertions(+), 53 deletions(-) diff --git a/src/libtomahawk/resolvers/QtScriptResolver.cpp b/src/libtomahawk/resolvers/QtScriptResolver.cpp index 37bf6964be..5a02fcaaaf 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.cpp +++ b/src/libtomahawk/resolvers/QtScriptResolver.cpp @@ -88,6 +88,8 @@ #include #include "qjson/serializer.h" + + //--- end includes readcloudfile // FIXME: bloody hack, remove this for 0.3 @@ -358,7 +360,9 @@ QtScriptResolverHelper::base64Decode( const QByteArray& input ) void -QtScriptResolverHelper::ReadCloudFile(const QString& fileName, const QString& fileId, const QString& sizeS, const QString& mime_type, const QVariant& requestJS, const QString& javascriptCallbackFunction, const QString& javascriptRefreshUrlFunction) +QtScriptResolverHelper::ReadCloudFile(const QString& fileName, const QString& fileId, const QString& sizeS, + const QString& mime_type, const QVariant& requestJS, const QString& javascriptCallbackFunction, + const QString& javascriptRefreshUrlFunction, const bool refreshUrlEachTime) { QVariantMap request; @@ -367,22 +371,24 @@ QtScriptResolverHelper::ReadCloudFile(const QString& fileName, const QString& fi QVariantMap m; long size = sizeS.toLong(); - + QString urlString; if(requestJS.type() == QVariant::Map) { request = requestJS.toMap(); - download_url = QUrl::fromUserInput(request["url"].toString()); + urlString = request["url"].toString(); headers = request["headers"].toMap(); } else { - download_url = QUrl::fromUserInput(requestJS.toString()); + urlString = requestJS.toString(); } + download_url.setUrl(urlString); + tDebug( LOGINFO ) << "#### ReadCloudFile : Loading tags of " << fileName << " from " << download_url.toString() << " which have id " << fileId; @@ -390,8 +396,9 @@ QtScriptResolverHelper::ReadCloudFile(const QString& fileName, const QString& fi m["mimetype"] = mime_type.toUtf8(); - CloudStream* stream = new CloudStream( - download_url, fileName, fileId, size, headers, network, m_resolver, javascriptRefreshUrlFunction); + CloudStream* stream = new CloudStream(download_url, fileName, fileId, + size, headers, network, m_resolver, + javascriptRefreshUrlFunction, refreshUrlEachTime); stream->Precache(); boost::scoped_ptr tag; if (mime_type == "audio/mpeg") { // && title.endsWith(".mp3")) { @@ -488,7 +495,6 @@ QtScriptResolverHelper::ReadCloudFile(const QString& fileName, const QString& fi m_resolver->m_engine->mainFrame()->evaluateJavaScript( getUrl ); } - void QtScriptResolverHelper::addLocalJSFile( const QString &jsFilePath ) { diff --git a/src/libtomahawk/resolvers/QtScriptResolver.h b/src/libtomahawk/resolvers/QtScriptResolver.h index cc824abf21..d9b2014e54 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.h +++ b/src/libtomahawk/resolvers/QtScriptResolver.h @@ -67,7 +67,9 @@ Q_OBJECT // send ID3Tags of the stream as argument of the callback function Q_INVOKABLE void - ReadCloudFile(const QString& fileName, const QString& fileId, const QString& sizeS, const QString& mime_type, const QVariant& requestJS, const QString& javascriptCallbackFunction, const QString& javascriptRefreshUrlFunction); + ReadCloudFile(const QString& fileName, const QString& fileId, const QString& sizeS, + const QString& mime_type, const QVariant& requestJS, const QString& javascriptCallbackFunction, + const QString& javascriptRefreshUrlFunction = QString(), const bool refreshUrlEachTime = false); Q_INVOKABLE void addLocalJSFile(const QString& jsFilePath); diff --git a/src/libtomahawk/utils/cloudstream.cpp b/src/libtomahawk/utils/cloudstream.cpp index b6da2c512d..639ca17b6f 100644 --- a/src/libtomahawk/utils/cloudstream.cpp +++ b/src/libtomahawk/utils/cloudstream.cpp @@ -41,7 +41,7 @@ const static int MAX_ALLOW_ERROR_QUERY = 2; CloudStream::CloudStream( QUrl& url, const QString& filename, const QString& fileId, const long length, QVariantMap& headers, QNetworkAccessManager* network, QtScriptResolver* scriptResolver, - const QString & javascriptRefreshUrlFunction) + const QString & javascriptRefreshUrlFunction, const bool refreshUrlEachTime) : url_(url), filename_(filename), fileId_(fileId), @@ -54,7 +54,8 @@ CloudStream::CloudStream( num_requests_(0), num_requests_in_error_(0), scriptResolver_(scriptResolver), - javascriptRefreshUrlFunction_(javascriptRefreshUrlFunction) { + javascriptRefreshUrlFunction_(javascriptRefreshUrlFunction), + refreshUrlEachTime_(refreshUrlEachTime){ tDebug( LOGINFO ) << "#### Cloudstream : CloudStream object created for " << filename_ << " : " << url_.toString(); } @@ -114,24 +115,31 @@ TagLib::ByteVector CloudStream::readBlock(ulong length) { const uint end = qMin(cursor_ + length - 1, length_ - 1); //tDebug( LOGINFO ) << "#### CloudStream : reading block from " << start << " to " << end << " for " << url_.toString(); - + tDebug( LOGINFO ) << "#### CloudStream : parsing from " << url_.toString(); + tDebug( LOGINFO ) << "#### CloudStream : parsing from (encoded) " << url_.toEncoded().constData(); if (end < start) { return TagLib::ByteVector(); } - if(num_requests_in_error_ > MAX_ALLOW_ERROR_QUERY){ - return TagLib::ByteVector(); - } - if (CheckCache(start, end)) { TagLib::ByteVector cached = GetCached(start, end); cursor_ += cached.size(); return cached; } + if(num_requests_in_error_ > MAX_ALLOW_ERROR_QUERY){ + return TagLib::ByteVector(); + } + + if(refreshUrlEachTime_){ + if(!refreshStreamUrl()){ + tDebug( LOGINFO ) << "#### CloudStream : cannot refresh streamUrl for " << filename_; + } + } + QNetworkRequest request = QNetworkRequest(url_); - //setings of specials OAuth (1 or 2) headers + //setings of specials OAuth (1 or 2) headers foreach(const QString& headerName, headers_.keys()) { request.setRawHeader(headerName.toLocal8Bit(), headers_[headerName].toString().toLocal8Bit()); @@ -163,55 +171,34 @@ TagLib::ByteVector CloudStream::readBlock(ulong length) { reply->deleteLater(); int code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - tDebug() << "######## CloudStream : HTTP reply : "; + tDebug() << "######### CloudStream : HTTP reply : #########"; tDebug( LOGINFO ) << "#### Cloudstream : HttpStatusCode : " << code; foreach (const QNetworkReply::RawHeaderPair& pair, reply->rawHeaderPairs()){ tDebug( LOGINFO ) << "#### Cloudstream : header reply " << pair; } + QByteArray data = reply->readAll(); + if (code != 206) { num_requests_in_error_++; tDebug( LOGINFO ) << "#### Cloudstream : Error " << code << " retrieving url to tag for " << filename_; - if(!javascriptRefreshUrlFunction_.isEmpty()){ - tDebug( LOGINFO ) << "####### Cloudstream : trying to get a good URL for " << fileId_; - QString refreshUrl = QString("resolver.%1( \"%2\" );").arg( javascriptRefreshUrlFunction_ ) - .arg( fileId_ ); - tDebug( LOGINFO ) << refreshUrl; - QVariant response = scriptResolver_->executeJavascript(refreshUrl); - - - if(response.isNull()){ - tDebug( LOGINFO ) << "####### Cloudstream : response is empty, returning" << response; - return TagLib::ByteVector(); - } - QVariantMap request; - if(response.type() == QVariant::Map) - { - request = response.toMap(); - - url_ = QUrl(request["url"].toString()); - - headers_ = request["headers"].toMap(); - } - else - { - url_ = QUrl(response.toString()); - } - - TagLib::ByteVector bytes = readBlock(length); - //if we have datas, let another chance to parse ID3Tags (especially for Dropbox) - if(bytes.size() > 0){ - tDebug( LOGINFO ) << "#### Cloudstream : we have a response !"; - num_requests_in_error_--; - } - return bytes; + tDebug() << "#### CloudStream : body response : " << data; + + if(refreshStreamUrl()) { + TagLib::ByteVector bytes = readBlock(length); + //if we have datas, let another chance to parse ID3Tags (especially for Dropbox) + if(bytes.size() > 0){ + tDebug( LOGINFO ) << "#### Cloudstream : we have datas response with the refreshUrl !"; + num_requests_in_error_--; + } + return bytes; } else { - return TagLib::ByteVector(); + return TagLib::ByteVector(); } } - QByteArray data = reply->readAll(); + TagLib::ByteVector bytes(data.data(), data.size()); cursor_ += data.size(); @@ -219,6 +206,41 @@ TagLib::ByteVector CloudStream::readBlock(ulong length) { return bytes; } +bool CloudStream::refreshStreamUrl() { + if(javascriptRefreshUrlFunction_.isEmpty()){ + return false; + } + tDebug( LOGINFO ) << "####### Cloudstream : refreshing streamUrl for " << filename_; + QString refreshUrl = QString("resolver.%1( \"%2\" );").arg( javascriptRefreshUrlFunction_ ).arg( fileId_ ); + tDebug( LOGINFO ) << "####### Cloudstream : refresh request : " << refreshUrl; + QVariant response = scriptResolver_->executeJavascript(refreshUrl); + + if(response.isNull()){ + tDebug( LOGINFO ) << "####### Cloudstream : refreshUrl response is empty, returning"; + return false; + } + + QVariantMap request; + QString urlString; + + if(response.type() == QVariant::Map) + { + request = response.toMap(); + + urlString = request["url"].toString(); + + headers_ = request["headers"].toMap(); + } + else + { + urlString = response.toString(); + } + + url_.setUrl(urlString); + tDebug( LOGINFO ) << "####### Cloudstream : streamUrl refreshed for " << filename_; + return true; +} + void CloudStream::writeBlock(const TagLib::ByteVector&) { tDebug( LOGINFO ) << "writeBlock not implemented"; } diff --git a/src/libtomahawk/utils/cloudstream.h b/src/libtomahawk/utils/cloudstream.h index 89725ea5c0..6e60ae3343 100644 --- a/src/libtomahawk/utils/cloudstream.h +++ b/src/libtomahawk/utils/cloudstream.h @@ -38,7 +38,10 @@ class CloudStream : public QObject, public TagLib::IOStream { const QString& fileId, const long length, QVariantMap& headers, - QNetworkAccessManager* network, QtScriptResolver *scriptResolver, const QString& javascriptRefreshUrlFunction); + QNetworkAccessManager* network, + QtScriptResolver *scriptResolver, + const QString& javascriptRefreshUrlFunction, + const bool refreshUrlEachTime); //Taglib::IOStream; virtual TagLib::FileName name() const; @@ -69,11 +72,14 @@ class CloudStream : public QObject, public TagLib::IOStream { // Use educated guess to request the bytes that TagLib will probably want. void Precache(); + bool refreshStreamUrl(); + private: bool CheckCache(int start, int end); void FillCache(int start, TagLib::ByteVector data); TagLib::ByteVector GetCached(int start, int end); + private slots: void SSLErrors(const QList& errors); @@ -85,6 +91,7 @@ class CloudStream : public QObject, public TagLib::IOStream { const ulong length_; QVariantMap headers_; const QString javascriptRefreshUrlFunction_; + const bool refreshUrlEachTime_; int cursor_; QNetworkAccessManager* network_; From 1605fe8986670223b4feaa44a201078e11c56038 Mon Sep 17 00:00:00 2001 From: loclamor Date: Thu, 28 Mar 2013 14:29:27 +0100 Subject: [PATCH 34/76] Style convention clean-up --- src/libtomahawk/CMakeLists.txt | 2 +- .../resolvers/QtScriptResolver.cpp | 155 ++++---- src/libtomahawk/resolvers/QtScriptResolver.h | 5 +- src/libtomahawk/utils/CloudStream.cpp | 364 ++++++++++++++++++ src/libtomahawk/utils/CloudStream.h | 109 ++++++ src/libtomahawk/utils/cloudstream.cpp | 304 --------------- src/libtomahawk/utils/cloudstream.h | 105 ----- 7 files changed, 543 insertions(+), 501 deletions(-) create mode 100644 src/libtomahawk/utils/CloudStream.cpp create mode 100644 src/libtomahawk/utils/CloudStream.h delete mode 100644 src/libtomahawk/utils/cloudstream.cpp delete mode 100644 src/libtomahawk/utils/cloudstream.h diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 89d760dcc7..13eb7efc42 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -115,7 +115,7 @@ set( libGuiSources utils/SharedTimeLine.cpp utils/WebResultHintChecker.cpp utils/NetworkReply.cpp - utils/cloudstream.cpp + utils/CloudStream.cpp widgets/AnimatedCounterLabel.cpp widgets/BasicHeader.cpp diff --git a/src/libtomahawk/resolvers/QtScriptResolver.cpp b/src/libtomahawk/resolvers/QtScriptResolver.cpp index 5a02fcaaaf..add0cc903d 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.cpp +++ b/src/libtomahawk/resolvers/QtScriptResolver.cpp @@ -58,9 +58,7 @@ #include //--- includes readcloudFile -//#include "taghandlers/tag.h" -# include "utils/cloudstream.h" - +#include "utils/CloudStream.h" #include #include #include @@ -84,12 +82,8 @@ #include #include #include - #include - #include "qjson/serializer.h" - - //--- end includes readcloudfile // FIXME: bloody hack, remove this for 0.3 @@ -360,8 +354,9 @@ QtScriptResolverHelper::base64Decode( const QByteArray& input ) void -QtScriptResolverHelper::ReadCloudFile(const QString& fileName, const QString& fileId, const QString& sizeS, - const QString& mime_type, const QVariant& requestJS, const QString& javascriptCallbackFunction, +QtScriptResolverHelper::readCloudFile(const QString& fileName, const QString& fileId, + const QString& sizeS, const QString& mime_type, + const QVariant& requestJS, const QString& javascriptCallbackFunction, const QString& javascriptRefreshUrlFunction, const bool refreshUrlEachTime) { @@ -374,7 +369,7 @@ QtScriptResolverHelper::ReadCloudFile(const QString& fileName, const QString& fi QString urlString; - if(requestJS.type() == QVariant::Map) + if ( requestJS.type() == QVariant::Map ) { request = requestJS.toMap(); @@ -387,7 +382,7 @@ QtScriptResolverHelper::ReadCloudFile(const QString& fileName, const QString& fi urlString = requestJS.toString(); } - download_url.setUrl(urlString); + download_url.setUrl( urlString ); tDebug( LOGINFO ) << "#### ReadCloudFile : Loading tags of " << fileName << " from " << download_url.toString() << " which have id " << fileId; @@ -396,101 +391,85 @@ QtScriptResolverHelper::ReadCloudFile(const QString& fileName, const QString& fi m["mimetype"] = mime_type.toUtf8(); - CloudStream* stream = new CloudStream(download_url, fileName, fileId, - size, headers, network, m_resolver, - javascriptRefreshUrlFunction, refreshUrlEachTime); + CloudStream* stream = new CloudStream( download_url, fileName, fileId, + size, headers, network, m_resolver, + javascriptRefreshUrlFunction, refreshUrlEachTime ); stream->Precache(); boost::scoped_ptr tag; - if (mime_type == "audio/mpeg") { // && title.endsWith(".mp3")) { - tag.reset(new TagLib::MPEG::File( - stream, // Takes ownership. - TagLib::ID3v2::FrameFactory::instance(), - TagLib::AudioProperties::Accurate)); - } else if (mime_type == "audio/mp4" || - (mime_type == "audio/mpeg")) { // && title.endsWith(".m4a"))) { - tag.reset(new TagLib::MP4::File( - stream, - true, - TagLib::AudioProperties::Accurate)); - } else if (mime_type == "application/ogg" || - mime_type == "audio/ogg") { - tag.reset(new TagLib::Ogg::Vorbis::File( - stream, - true, - TagLib::AudioProperties::Accurate)); + if ( mime_type == "audio/mpeg" ) // && title.endsWith(".mp3")) + { + tag.reset(new TagLib::MPEG::File( + stream, // Takes ownership. + TagLib::ID3v2::FrameFactory::instance(), + TagLib::AudioProperties::Accurate)); + } + else if ( mime_type == "audio/mp4" || ( mime_type == "audio/mpeg" ) ) // && title.endsWith(".m4a"))) + { + tag.reset( new TagLib::MP4::File( stream, true, TagLib::AudioProperties::Accurate ) ); + } + else if ( mime_type == "application/ogg" || mime_type == "audio/ogg" ) + { + tag.reset(new TagLib::Ogg::Vorbis::File( stream, true, TagLib::AudioProperties::Accurate ) ); + } +#ifdef TAGLIB_HAS_OPUS + else if ( mime_type == "application/opus" || mime_type == "audio/opus" ) + { + tag.reset(new TagLib::Ogg::Opus::File( stream, true, TagLib::AudioProperties::Accurate ) ); + } +#endif + else if ( mime_type == "application/x-flac" || mime_type == "audio/flac" ) + { + tag.reset(new TagLib::FLAC::File( stream, TagLib::ID3v2::FrameFactory::instance(), true, + TagLib::AudioProperties::Accurate ) ); } - #ifdef TAGLIB_HAS_OPUS - else if (mime_type == "application/opus" || - mime_type == "audio/opus") { - tag.reset(new TagLib::Ogg::Opus::File( - stream, - true, - TagLib::AudioProperties::Accurate)); + else if ( mime_type == "audio/x-ms-wma" ) + { + tag.reset( new TagLib::ASF::File( stream, true, TagLib::AudioProperties::Accurate ) ); } - #endif - else if (mime_type == "application/x-flac" || - mime_type == "audio/flac") { - tag.reset(new TagLib::FLAC::File( - stream, - TagLib::ID3v2::FrameFactory::instance(), - true, - TagLib::AudioProperties::Accurate)); - } else if (mime_type == "audio/x-ms-wma") { - tag.reset(new TagLib::ASF::File( - stream, - true, - TagLib::AudioProperties::Accurate)); - } else { - tDebug( LOGINFO ) << "Unknown mime type for tagging:" << mime_type; - //return m; + else + { + tDebug( LOGINFO ) << "Unknown mime type for tagging:" << mime_type; } if (stream->num_requests() > 2) { - // Warn if pre-caching failed. - tDebug( LOGINFO ) << "Total requests for file:" << fileName - << stream->num_requests() - << stream->cached_bytes(); + // Warn if pre-caching failed. + tDebug( LOGINFO ) << "Total requests for file:" << fileName + << " : " << stream->num_requests() << " with " + << stream->cached_bytes() << " bytes cached"; } //construction of the tag's map - if (tag->tag() && !tag->tag()->isEmpty()) { - - m["track"] = tag->tag()->title().toCString(true); - m["artist"] = tag->tag()->artist().toCString(true); - m["album"] = tag->tag()->album().toCString(true); - m["size"] = QString::number(size); - - if (tag->tag()->track() != 0) { - m["albumpos"] = tag->tag()->track(); - } - if (tag->tag()->year() != 0) { - m["year"] = tag->tag()->year(); - } - - if (tag->audioProperties()) { - m["duration"] = tag->audioProperties()->length(); - m["bitrate"] = tag->audioProperties()->bitrate(); - } -/* if (tag->tag()->albumArtist()) { - m["albumartist"] = tag->tag()->albumArtist(); - } - if (tag->tag()->composer()) { - m["composer"] = tag->tag()->composer(); - } - if (tag->tag()->discNumber() != 0) { - m["discnumber"] = tag->tag()->discNumber(); - } -*/ + if ( tag->tag() && !tag->tag()->isEmpty() ) + { + m["track"] = tag->tag()->title().toCString( true ); + m["artist"] = tag->tag()->artist().toCString( true ); + m["album"] = tag->tag()->album().toCString( true ); + m["size"] = QString::number( size ); + + if ( tag->tag()->track() != 0 ) + { + m["albumpos"] = tag->tag()->track(); + } + if ( tag->tag()->year() != 0 ) + { + m["year"] = tag->tag()->year(); + } + + if ( tag->audioProperties() ) + { + m["duration"] = tag->audioProperties()->length(); + m["bitrate"] = tag->audioProperties()->bitrate(); + } } QJson::Serializer serializer; - QByteArray json = serializer.serialize(m); + QByteArray json = serializer.serialize( m ); tDebug() << "#### ReadCloudFile : Sending tags to js : " << json; QString getUrl = QString( "Tomahawk.resolver.instance.%1( %2 );" ).arg( javascriptCallbackFunction ) - .arg( QString(json) ); + .arg( QString(json) ); m_resolver->m_engine->mainFrame()->evaluateJavaScript( getUrl ); } diff --git a/src/libtomahawk/resolvers/QtScriptResolver.h b/src/libtomahawk/resolvers/QtScriptResolver.h index d9b2014e54..2ad3530365 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.h +++ b/src/libtomahawk/resolvers/QtScriptResolver.h @@ -66,10 +66,9 @@ Q_OBJECT // send ID3Tags of the stream as argument of the callback function - Q_INVOKABLE void - ReadCloudFile(const QString& fileName, const QString& fileId, const QString& sizeS, + Q_INVOKABLE void readCloudFile( const QString& fileName, const QString& fileId, const QString& sizeS, const QString& mime_type, const QVariant& requestJS, const QString& javascriptCallbackFunction, - const QString& javascriptRefreshUrlFunction = QString(), const bool refreshUrlEachTime = false); + const QString& javascriptRefreshUrlFunction = QString(), const bool refreshUrlEachTime = false ); Q_INVOKABLE void addLocalJSFile(const QString& jsFilePath); diff --git a/src/libtomahawk/utils/CloudStream.cpp b/src/libtomahawk/utils/CloudStream.cpp new file mode 100644 index 0000000000..16122e4ee6 --- /dev/null +++ b/src/libtomahawk/utils/CloudStream.cpp @@ -0,0 +1,364 @@ +/* This file is part of Clementine. + Copyright 2012, David Sansome + + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Clementine is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Clementine. If not, see . +*/ + +#include "CloudStream.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "utils/Logger.h" + +#include "resolvers/QtScriptResolver.h" + +namespace +{ + static const int kTaglibPrefixCacheBytes = 64 * 1024; // Should be enough. + static const int kTaglibSuffixCacheBytes = 8 * 1024; +} + +const static int MAX_ALLOW_ERROR_QUERY = 2; + +CloudStream::CloudStream( QUrl& url, + const QString& filename, + const QString& fileId, + const long length, + QVariantMap& headers, + QNetworkAccessManager* network, + QtScriptResolver* scriptResolver, + const QString & javascriptRefreshUrlFunction, + const bool refreshUrlEachTime ) + : m_url( url ) + , m_filename( filename ) + , m_fileId( fileId ) + , m_encoded_filename( m_filename.toUtf8() ) + , m_length( length ) + , m_headers( headers ) + , m_cursor( 0 ) + , m_network( network ) + , m_cache( length ) + , m_num_requests( 0 ) + , m_num_requests_in_error( 0 ) + , m_scriptResolver( scriptResolver ) + , m_javascriptRefreshUrlFunction( javascriptRefreshUrlFunction ) + , m_refreshUrlEachTime( refreshUrlEachTime ) +{ + tDebug( LOGINFO ) << "#### Cloudstream : CloudStream object created for " << m_filename << " : " + << m_url.toString(); +} + +TagLib::FileName +CloudStream::name() const +{ + return m_encoded_filename.data(); +} + +bool +CloudStream::CheckCache( int start, int end ) +{ + for ( int i = start; i <= end; ++i ) { + if ( !m_cache.test( i ) ) { + return false; + } + } + return true; +} + +void +CloudStream::FillCache( int start, TagLib::ByteVector data ) +{ + for ( int i = 0; i < data.size(); ++i ) + { + m_cache.set( start + i, data[i] ); + } +} + +TagLib::ByteVector +CloudStream::GetCached( int start, int end ) +{ + const uint size = end - start + 1; + TagLib::ByteVector ret( size ); + for ( int i = 0; i < size; ++i ) + { + ret[i] = m_cache.get( start + i ); + } + return ret; +} + +void +CloudStream::Precache() +{ + // For reading the tags of an MP3, TagLib tends to request: + // 1. The first 1024 bytes + // 2. Somewhere between the first 2KB and first 60KB + // 3. The last KB or two. + // 4. Somewhere in the first 64KB again + // + // OGG Vorbis may read the last 4KB. + // + // So, if we precache the first 64KB and the last 8KB we should be sorted :-) + // Ideally, we would use bytes=0-655364,-8096 but Google Drive does not seem + // to support multipart byte ranges yet so we have to make do with two + // requests. + tDebug( LOGINFO ) << "#### CloudStream : Precaching from :" << m_filename; + seek( 0, TagLib::IOStream::Beginning ); + readBlock( kTaglibPrefixCacheBytes ); + seek( kTaglibSuffixCacheBytes, TagLib::IOStream::End ); + readBlock( kTaglibSuffixCacheBytes ); + clear(); + tDebug( LOGINFO ) << "#### CloudStream : Precaching end for :" << m_filename; +} + +TagLib::ByteVector +CloudStream::readBlock( ulong length ) +{ + + const uint start = m_cursor; + const uint end = qMin( m_cursor + length - 1, m_length - 1 ); + + tDebug( LOGINFO ) << "#### CloudStream : parsing from " << m_url.toString(); + tDebug( LOGINFO ) << "#### CloudStream : parsing from (encoded) " << m_url.toEncoded().constData(); + if ( end < start ) + { + return TagLib::ByteVector(); + } + + if ( CheckCache( start, end ) ) + { + TagLib::ByteVector cached = GetCached( start, end ); + m_cursor += cached.size(); + return cached; + } + + if ( m_num_requests_in_error > MAX_ALLOW_ERROR_QUERY ) + { + return TagLib::ByteVector(); + } + + if ( m_refreshUrlEachTime ) + { + if( !refreshStreamUrl() ) + { + tDebug( LOGINFO ) << "#### CloudStream : cannot refresh streamUrl for " << m_filename; + } + } + + QNetworkRequest request = QNetworkRequest( m_url ); + + //setings of specials OAuth (1 or 2) headers + foreach ( const QString& headerName, m_headers.keys() ) + { + request.setRawHeader( headerName.toLocal8Bit(), m_headers[headerName].toString().toLocal8Bit() ); + + } + + request.setRawHeader( "Range", QString( "bytes=%1-%2" ).arg( start ).arg( end ).toUtf8() ); + request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork ); + // The Ubuntu One server applies the byte range to the gzipped data, rather + // than the raw data so we must disable compression. + if ( m_url.host() == "files.one.ubuntu.com" ) + { + request.setRawHeader( "Accept-Encoding", "identity" ); + } + + //tDebug() << request.rawHeader("Authorization"); + tDebug() << "######## CloudStream : HTTP request : "; + foreach ( const QByteArray& header, request.rawHeaderList() ) + { + tDebug() << "#### CloudStream : header request : " << header << " = " << request.rawHeader(header); + } + + QNetworkReply* reply = m_network->get( request ); + connect( reply, SIGNAL( sslErrors( QList ) ), SLOT( SSLErrors( QList ) ) ); + ++m_num_requests; + + QEventLoop loop; + QObject::connect( reply, SIGNAL( finished() ), &loop, SLOT( quit() ) ); + loop.exec(); + reply->deleteLater(); + + int code = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt(); + tDebug() << "######### CloudStream : HTTP reply : #########"; + tDebug( LOGINFO ) << "#### Cloudstream : HttpStatusCode : " << code; + foreach ( const QNetworkReply::RawHeaderPair& pair, reply->rawHeaderPairs() ) + { + tDebug( LOGINFO ) << "#### Cloudstream : header reply " << pair; + } + + QByteArray data = reply->readAll(); + + if ( code != 206 ) + { + m_num_requests_in_error++; + tDebug( LOGINFO ) << "#### Cloudstream : Error " << code << " retrieving url to tag for " << m_filename; + tDebug() << "#### CloudStream : body response : " << data; + + if ( refreshStreamUrl() ) + { + TagLib::ByteVector bytes = readBlock( length ); + //if we have datas, let another chance to parse ID3Tags (especially for Dropbox) + if( bytes.size() > 0 ){ + tDebug( LOGINFO ) << "#### Cloudstream : we have datas response with the refreshUrl !"; + m_num_requests_in_error--; + } + return bytes; + } + else + { + return TagLib::ByteVector(); + } + } + + + TagLib::ByteVector bytes( data.data(), data.size() ); + m_cursor += data.size(); + + FillCache( start, bytes ); + return bytes; +} + +bool +CloudStream::refreshStreamUrl() +{ + if ( m_javascriptRefreshUrlFunction.isEmpty() ) + { + return false; + } + tDebug( LOGINFO ) << "####### Cloudstream : refreshing streamUrl for " << m_filename; + QString refreshUrl = QString( "resolver.%1( \"%2\" );" ).arg( m_javascriptRefreshUrlFunction ) + .arg( m_fileId ); + tDebug( LOGINFO ) << "####### Cloudstream : refresh request : " << refreshUrl; + QVariant response = m_scriptResolver->executeJavascript( refreshUrl ); + + if ( response.isNull() ) + { + tDebug( LOGINFO ) << "####### Cloudstream : refreshUrl response is empty, returning"; + return false; + } + + QVariantMap request; + QString urlString; + + if ( response.type() == QVariant::Map ) + { + request = response.toMap(); + + urlString = request["url"].toString(); + + m_headers = request["headers"].toMap(); + } + else + { + urlString = response.toString(); + } + + m_url.setUrl( urlString ); + tDebug( LOGINFO ) << "####### Cloudstream : streamUrl refreshed for " << m_filename; + return true; +} + +void +CloudStream::writeBlock( const TagLib::ByteVector& ) +{ + tDebug( LOGINFO ) << "writeBlock not implemented"; +} + +void +CloudStream::insert( const TagLib::ByteVector&, ulong, ulong ) +{ + tDebug( LOGINFO ) << "insert not implemented"; +} + +void +CloudStream::removeBlock( ulong, ulong ) +{ + tDebug( LOGINFO ) << "removeBlock not implemented"; +} + +bool +CloudStream::readOnly() const +{ + tDebug( LOGINFO ) << "readOnly not implemented"; + return true; +} + +bool +CloudStream::isOpen() const +{ + return true; +} + +void +CloudStream::seek( long offset, TagLib::IOStream::Position p ) +{ + switch ( p ) + { + case TagLib::IOStream::Beginning: + m_cursor = offset; + break; + + case TagLib::IOStream::Current: + m_cursor = qMin( ulong( m_cursor + offset ), m_length ); + break; + + case TagLib::IOStream::End: + // This should really not have qAbs(), but OGG reading needs it. + m_cursor = qMax( 0UL, m_length - qAbs( offset ) ); + break; + } +} + +void +CloudStream::clear() +{ + m_cursor = 0; +} + +long +CloudStream::tell() const +{ + return m_cursor; +} + +long +CloudStream::length() +{ + return m_length; +} + +void +CloudStream::truncate( long ) +{ + tDebug( LOGINFO ) << "not implemented"; +} + +void +CloudStream::SSLErrors( const QList& errors ) +{ + foreach ( const QSslError& error, errors ) + { + tDebug( LOGINFO ) << "#### Cloudstream : Error for " << m_filename << " : "; + tDebug( LOGINFO ) << error.error() << error.errorString(); + tDebug( LOGINFO ) << error.certificate(); + } +} diff --git a/src/libtomahawk/utils/CloudStream.h b/src/libtomahawk/utils/CloudStream.h new file mode 100644 index 0000000000..57ae132b9b --- /dev/null +++ b/src/libtomahawk/utils/CloudStream.h @@ -0,0 +1,109 @@ +/* This file is part of Clementine. + Copyright 2012, David Sansome + + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Clementine is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Clementine. If not, see . +*/ + +//#ifndef GOOGLEDRIVESTREAM_H +//#define GOOGLEDRIVESTREAM_H + +#include +#include +#include +#include + + +#include +#include + +class QNetworkAccessManager; +class QtScriptResolver; + +class CloudStream : public QObject, public TagLib::IOStream +{ + Q_OBJECT +public: + CloudStream( QUrl& url, + const QString& filename, + const QString& fileId, + const long length, + QVariantMap& headers, + QNetworkAccessManager* network, + QtScriptResolver *scriptResolver, + const QString& javascriptRefreshUrlFunction, + const bool refreshUrlEachTime ); + + //Taglib::IOStream; + virtual TagLib::FileName name() const; + virtual TagLib::ByteVector readBlock( ulong length ); + virtual void writeBlock( const TagLib::ByteVector& ); + virtual void insert( const TagLib::ByteVector&, ulong, ulong ); + virtual void removeBlock( ulong, ulong ); + virtual bool readOnly() const; + virtual bool isOpen() const; + virtual void seek( long offset, TagLib::IOStream::Position p ); + virtual void clear(); + virtual long tell() const; + virtual long length(); + virtual void truncate( long ); + + google::sparsetable::size_type cached_bytes() const + { + return m_cache.num_nonempty(); + } + + int num_requests() const + { + return m_num_requests; + } + + int num_requests_in_error() const + { + return m_num_requests_in_error; + } + + // Use educated guess to request the bytes that TagLib will probably want. + void Precache(); + + bool refreshStreamUrl(); + +private: + bool CheckCache( int start, int end ); + void FillCache( int start, TagLib::ByteVector data ); + TagLib::ByteVector GetCached( int start, int end ); + + +private slots: + void SSLErrors( const QList& errors ); + +private: + QUrl m_url; + const QString m_filename; + const QString m_fileId; + const QByteArray m_encoded_filename; + const ulong m_length; + QVariantMap m_headers; + const QString m_javascriptRefreshUrlFunction; + const bool m_refreshUrlEachTime; + + int m_cursor; + QNetworkAccessManager* m_network; + QtScriptResolver* m_scriptResolver; + + google::sparsetable m_cache; + int m_num_requests; + int m_num_requests_in_error; +}; + +//#endif // GOOGLEDRIVESTREAM_H diff --git a/src/libtomahawk/utils/cloudstream.cpp b/src/libtomahawk/utils/cloudstream.cpp deleted file mode 100644 index 639ca17b6f..0000000000 --- a/src/libtomahawk/utils/cloudstream.cpp +++ /dev/null @@ -1,304 +0,0 @@ -/* This file is part of Clementine. - Copyright 2012, David Sansome - - Clementine is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Clementine is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Clementine. If not, see . -*/ - -#include "cloudstream.h" - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "utils/Logger.h" - -#include "resolvers/QtScriptResolver.h" - -namespace { - static const int kTaglibPrefixCacheBytes = 64 * 1024; // Should be enough. - static const int kTaglibSuffixCacheBytes = 8 * 1024; -} - -const static int MAX_ALLOW_ERROR_QUERY = 2; - -CloudStream::CloudStream( - QUrl& url, const QString& filename, const QString& fileId, const long length, - QVariantMap& headers, QNetworkAccessManager* network, QtScriptResolver* scriptResolver, - const QString & javascriptRefreshUrlFunction, const bool refreshUrlEachTime) - : url_(url), - filename_(filename), - fileId_(fileId), - encoded_filename_(filename_.toUtf8()), - length_(length), - headers_(headers), - cursor_(0), - network_(network), - cache_(length), - num_requests_(0), - num_requests_in_error_(0), - scriptResolver_(scriptResolver), - javascriptRefreshUrlFunction_(javascriptRefreshUrlFunction), - refreshUrlEachTime_(refreshUrlEachTime){ - tDebug( LOGINFO ) << "#### Cloudstream : CloudStream object created for " << filename_ << " : " << url_.toString(); -} - -TagLib::FileName CloudStream::name() const { - return encoded_filename_.data(); -} - -bool CloudStream::CheckCache(int start, int end) { - for (int i = start; i <= end; ++i) { - if (!cache_.test(i)) { - return false; - } - } - return true; -} - -void CloudStream::FillCache(int start, TagLib::ByteVector data) { - for (int i = 0; i < data.size(); ++i) { - cache_.set(start + i, data[i]); - } -} - -TagLib::ByteVector CloudStream::GetCached(int start, int end) { - const uint size = end - start + 1; - TagLib::ByteVector ret(size); - for (int i = 0; i < size; ++i) { - ret[i] = cache_.get(start + i); - } - return ret; -} - -void CloudStream::Precache() { - // For reading the tags of an MP3, TagLib tends to request: - // 1. The first 1024 bytes - // 2. Somewhere between the first 2KB and first 60KB - // 3. The last KB or two. - // 4. Somewhere in the first 64KB again - // - // OGG Vorbis may read the last 4KB. - // - // So, if we precache the first 64KB and the last 8KB we should be sorted :-) - // Ideally, we would use bytes=0-655364,-8096 but Google Drive does not seem - // to support multipart byte ranges yet so we have to make do with two - // requests. - tDebug( LOGINFO ) << "#### CloudStream : Precaching from :" << filename_; - seek(0, TagLib::IOStream::Beginning); - readBlock(kTaglibPrefixCacheBytes); - seek(kTaglibSuffixCacheBytes, TagLib::IOStream::End); - readBlock(kTaglibSuffixCacheBytes); - clear(); - tDebug( LOGINFO ) << "#### CloudStream : Precaching end for :" << filename_; -} - -TagLib::ByteVector CloudStream::readBlock(ulong length) { - - const uint start = cursor_; - const uint end = qMin(cursor_ + length - 1, length_ - 1); - - //tDebug( LOGINFO ) << "#### CloudStream : reading block from " << start << " to " << end << " for " << url_.toString(); - tDebug( LOGINFO ) << "#### CloudStream : parsing from " << url_.toString(); - tDebug( LOGINFO ) << "#### CloudStream : parsing from (encoded) " << url_.toEncoded().constData(); - if (end < start) { - return TagLib::ByteVector(); - } - - if (CheckCache(start, end)) { - TagLib::ByteVector cached = GetCached(start, end); - cursor_ += cached.size(); - return cached; - } - - if(num_requests_in_error_ > MAX_ALLOW_ERROR_QUERY){ - return TagLib::ByteVector(); - } - - if(refreshUrlEachTime_){ - if(!refreshStreamUrl()){ - tDebug( LOGINFO ) << "#### CloudStream : cannot refresh streamUrl for " << filename_; - } - } - - QNetworkRequest request = QNetworkRequest(url_); - - //setings of specials OAuth (1 or 2) headers - foreach(const QString& headerName, headers_.keys()) { - request.setRawHeader(headerName.toLocal8Bit(), headers_[headerName].toString().toLocal8Bit()); - - } - - request.setRawHeader( - "Range", QString("bytes=%1-%2").arg(start).arg(end).toUtf8()); - request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, - QNetworkRequest::AlwaysNetwork); - // The Ubuntu One server applies the byte range to the gzipped data, rather - // than the raw data so we must disable compression. - if (url_.host() == "files.one.ubuntu.com") { - request.setRawHeader("Accept-Encoding", "identity"); - } - - //tDebug() << request.rawHeader("Authorization"); - tDebug() << "######## CloudStream : HTTP request : "; - foreach(const QByteArray& header, request.rawHeaderList()){ - tDebug() << "#### CloudStream : header request : " << header << " = " << request.rawHeader(header); - } - - QNetworkReply* reply = network_->get(request); - connect(reply, SIGNAL(sslErrors(QList)), SLOT(SSLErrors(QList))); - ++num_requests_; - - QEventLoop loop; - QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); - loop.exec(); - reply->deleteLater(); - - int code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - tDebug() << "######### CloudStream : HTTP reply : #########"; - tDebug( LOGINFO ) << "#### Cloudstream : HttpStatusCode : " << code; - foreach (const QNetworkReply::RawHeaderPair& pair, reply->rawHeaderPairs()){ - tDebug( LOGINFO ) << "#### Cloudstream : header reply " << pair; - } - - QByteArray data = reply->readAll(); - - if (code != 206) { - num_requests_in_error_++; - tDebug( LOGINFO ) << "#### Cloudstream : Error " << code << " retrieving url to tag for " << filename_; - tDebug() << "#### CloudStream : body response : " << data; - - if(refreshStreamUrl()) { - TagLib::ByteVector bytes = readBlock(length); - //if we have datas, let another chance to parse ID3Tags (especially for Dropbox) - if(bytes.size() > 0){ - tDebug( LOGINFO ) << "#### Cloudstream : we have datas response with the refreshUrl !"; - num_requests_in_error_--; - } - return bytes; - } - else { - return TagLib::ByteVector(); - } - } - - - TagLib::ByteVector bytes(data.data(), data.size()); - cursor_ += data.size(); - - FillCache(start, bytes); - return bytes; -} - -bool CloudStream::refreshStreamUrl() { - if(javascriptRefreshUrlFunction_.isEmpty()){ - return false; - } - tDebug( LOGINFO ) << "####### Cloudstream : refreshing streamUrl for " << filename_; - QString refreshUrl = QString("resolver.%1( \"%2\" );").arg( javascriptRefreshUrlFunction_ ).arg( fileId_ ); - tDebug( LOGINFO ) << "####### Cloudstream : refresh request : " << refreshUrl; - QVariant response = scriptResolver_->executeJavascript(refreshUrl); - - if(response.isNull()){ - tDebug( LOGINFO ) << "####### Cloudstream : refreshUrl response is empty, returning"; - return false; - } - - QVariantMap request; - QString urlString; - - if(response.type() == QVariant::Map) - { - request = response.toMap(); - - urlString = request["url"].toString(); - - headers_ = request["headers"].toMap(); - } - else - { - urlString = response.toString(); - } - - url_.setUrl(urlString); - tDebug( LOGINFO ) << "####### Cloudstream : streamUrl refreshed for " << filename_; - return true; -} - -void CloudStream::writeBlock(const TagLib::ByteVector&) { - tDebug( LOGINFO ) << "writeBlock not implemented"; -} - -void CloudStream::insert(const TagLib::ByteVector&, ulong, ulong) { - tDebug( LOGINFO ) << "insert not implemented"; -} - -void CloudStream::removeBlock(ulong, ulong) { - tDebug( LOGINFO ) << "removeBlock not implemented"; -} - -bool CloudStream::readOnly() const { - tDebug( LOGINFO ) << "readOnly not implemented"; - return true; -} - -bool CloudStream::isOpen() const { - return true; -} - -void CloudStream::seek(long offset, TagLib::IOStream::Position p) { - switch (p) { - case TagLib::IOStream::Beginning: - cursor_ = offset; - break; - - case TagLib::IOStream::Current: - cursor_ = qMin(ulong(cursor_ + offset), length_); - break; - - case TagLib::IOStream::End: - // This should really not have qAbs(), but OGG reading needs it. - cursor_ = qMax(0UL, length_ - qAbs(offset)); - break; - } -} - -void CloudStream::clear() { - cursor_ = 0; -} - -long CloudStream::tell() const { - return cursor_; -} - -long CloudStream::length() { - return length_; -} - -void CloudStream::truncate(long) { - tDebug( LOGINFO ) << "not implemented"; -} - -void CloudStream::SSLErrors(const QList& errors) { - foreach (const QSslError& error, errors) { - tDebug( LOGINFO ) << "#### Cloudstream : Error for " << filename_ << " : "; - tDebug( LOGINFO ) << error.error() << error.errorString(); - tDebug( LOGINFO ) << error.certificate(); - } -} diff --git a/src/libtomahawk/utils/cloudstream.h b/src/libtomahawk/utils/cloudstream.h deleted file mode 100644 index 6e60ae3343..0000000000 --- a/src/libtomahawk/utils/cloudstream.h +++ /dev/null @@ -1,105 +0,0 @@ -/* This file is part of Clementine. - Copyright 2012, David Sansome - - Clementine is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Clementine is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Clementine. If not, see . -*/ - -//#ifndef GOOGLEDRIVESTREAM_H -//#define GOOGLEDRIVESTREAM_H - -#include -#include -#include -#include - - -#include -#include - -class QNetworkAccessManager; -class QtScriptResolver; - -class CloudStream : public QObject, public TagLib::IOStream { - Q_OBJECT - public: - CloudStream(QUrl& url, - const QString& filename, - const QString& fileId, - const long length, - QVariantMap& headers, - QNetworkAccessManager* network, - QtScriptResolver *scriptResolver, - const QString& javascriptRefreshUrlFunction, - const bool refreshUrlEachTime); - - //Taglib::IOStream; - virtual TagLib::FileName name() const; - virtual TagLib::ByteVector readBlock(ulong length); - virtual void writeBlock(const TagLib::ByteVector&); - virtual void insert(const TagLib::ByteVector&, ulong, ulong); - virtual void removeBlock(ulong, ulong); - virtual bool readOnly() const; - virtual bool isOpen() const; - virtual void seek(long offset, TagLib::IOStream::Position p); - virtual void clear(); - virtual long tell() const; - virtual long length(); - virtual void truncate(long); - - google::sparsetable::size_type cached_bytes() const { - return cache_.num_nonempty(); - } - - int num_requests() const { - return num_requests_; - } - - int num_requests_in_error() const { - return num_requests_in_error_; - } - - // Use educated guess to request the bytes that TagLib will probably want. - void Precache(); - - bool refreshStreamUrl(); - - private: - bool CheckCache(int start, int end); - void FillCache(int start, TagLib::ByteVector data); - TagLib::ByteVector GetCached(int start, int end); - - - private slots: - void SSLErrors(const QList& errors); - - private: - QUrl url_; - const QString filename_; - const QString fileId_; - const QByteArray encoded_filename_; - const ulong length_; - QVariantMap headers_; - const QString javascriptRefreshUrlFunction_; - const bool refreshUrlEachTime_; - - int cursor_; - QNetworkAccessManager* network_; - QtScriptResolver* scriptResolver_; - - google::sparsetable cache_; - int num_requests_; - int num_requests_in_error_; -}; - -//#endif // GOOGLEDRIVESTREAM_H From d63100bdb52ce2031359770bda5e5c18838e9b97 Mon Sep 17 00:00:00 2001 From: loclamor Date: Wed, 27 Mar 2013 20:39:28 +0100 Subject: [PATCH 35/76] add a refreshUrlEachTime parameter to cloudstream and readCloudStream ; separate the refresh url code in a dedicated function --- .../resolvers/QtScriptResolver.cpp | 20 ++-- src/libtomahawk/resolvers/QtScriptResolver.h | 4 +- src/libtomahawk/utils/cloudstream.cpp | 110 +++++++++++------- src/libtomahawk/utils/cloudstream.h | 9 +- 4 files changed, 90 insertions(+), 53 deletions(-) diff --git a/src/libtomahawk/resolvers/QtScriptResolver.cpp b/src/libtomahawk/resolvers/QtScriptResolver.cpp index 84cba51e96..372a154667 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.cpp +++ b/src/libtomahawk/resolvers/QtScriptResolver.cpp @@ -88,6 +88,8 @@ #include #include "qjson/serializer.h" + + //--- end includes readcloudfile // FIXME: bloody hack, remove this for 0.3 @@ -358,7 +360,9 @@ QtScriptResolverHelper::base64Decode( const QByteArray& input ) void -QtScriptResolverHelper::ReadCloudFile(const QString& fileName, const QString& fileId, const QString& sizeS, const QString& mime_type, const QVariant& requestJS, const QString& javascriptCallbackFunction, const QString& javascriptRefreshUrlFunction) +QtScriptResolverHelper::ReadCloudFile(const QString& fileName, const QString& fileId, const QString& sizeS, + const QString& mime_type, const QVariant& requestJS, const QString& javascriptCallbackFunction, + const QString& javascriptRefreshUrlFunction, const bool refreshUrlEachTime) { QVariantMap request; @@ -367,22 +371,24 @@ QtScriptResolverHelper::ReadCloudFile(const QString& fileName, const QString& fi QVariantMap m; long size = sizeS.toLong(); - + QString urlString; if(requestJS.type() == QVariant::Map) { request = requestJS.toMap(); - download_url = QUrl::fromUserInput(request["url"].toString()); + urlString = request["url"].toString(); headers = request["headers"].toMap(); } else { - download_url = QUrl::fromUserInput(requestJS.toString()); + urlString = requestJS.toString(); } + download_url.setUrl(urlString); + tDebug( LOGINFO ) << "#### ReadCloudFile : Loading tags of " << fileName << " from " << download_url.toString() << " which have id " << fileId; @@ -390,8 +396,9 @@ QtScriptResolverHelper::ReadCloudFile(const QString& fileName, const QString& fi m["mimetype"] = mime_type.toUtf8(); - CloudStream* stream = new CloudStream( - download_url, fileName, fileId, size, headers, network, m_resolver, javascriptRefreshUrlFunction); + CloudStream* stream = new CloudStream(download_url, fileName, fileId, + size, headers, network, m_resolver, + javascriptRefreshUrlFunction, refreshUrlEachTime); stream->Precache(); boost::scoped_ptr tag; if (mime_type == "audio/mpeg") { // && title.endsWith(".mp3")) { @@ -488,7 +495,6 @@ QtScriptResolverHelper::ReadCloudFile(const QString& fileName, const QString& fi m_resolver->m_engine->mainFrame()->evaluateJavaScript( getUrl ); } - void QtScriptResolverHelper::addLocalJSFile( const QString &jsFilePath ) { diff --git a/src/libtomahawk/resolvers/QtScriptResolver.h b/src/libtomahawk/resolvers/QtScriptResolver.h index cc824abf21..d9b2014e54 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.h +++ b/src/libtomahawk/resolvers/QtScriptResolver.h @@ -67,7 +67,9 @@ Q_OBJECT // send ID3Tags of the stream as argument of the callback function Q_INVOKABLE void - ReadCloudFile(const QString& fileName, const QString& fileId, const QString& sizeS, const QString& mime_type, const QVariant& requestJS, const QString& javascriptCallbackFunction, const QString& javascriptRefreshUrlFunction); + ReadCloudFile(const QString& fileName, const QString& fileId, const QString& sizeS, + const QString& mime_type, const QVariant& requestJS, const QString& javascriptCallbackFunction, + const QString& javascriptRefreshUrlFunction = QString(), const bool refreshUrlEachTime = false); Q_INVOKABLE void addLocalJSFile(const QString& jsFilePath); diff --git a/src/libtomahawk/utils/cloudstream.cpp b/src/libtomahawk/utils/cloudstream.cpp index b6da2c512d..639ca17b6f 100644 --- a/src/libtomahawk/utils/cloudstream.cpp +++ b/src/libtomahawk/utils/cloudstream.cpp @@ -41,7 +41,7 @@ const static int MAX_ALLOW_ERROR_QUERY = 2; CloudStream::CloudStream( QUrl& url, const QString& filename, const QString& fileId, const long length, QVariantMap& headers, QNetworkAccessManager* network, QtScriptResolver* scriptResolver, - const QString & javascriptRefreshUrlFunction) + const QString & javascriptRefreshUrlFunction, const bool refreshUrlEachTime) : url_(url), filename_(filename), fileId_(fileId), @@ -54,7 +54,8 @@ CloudStream::CloudStream( num_requests_(0), num_requests_in_error_(0), scriptResolver_(scriptResolver), - javascriptRefreshUrlFunction_(javascriptRefreshUrlFunction) { + javascriptRefreshUrlFunction_(javascriptRefreshUrlFunction), + refreshUrlEachTime_(refreshUrlEachTime){ tDebug( LOGINFO ) << "#### Cloudstream : CloudStream object created for " << filename_ << " : " << url_.toString(); } @@ -114,24 +115,31 @@ TagLib::ByteVector CloudStream::readBlock(ulong length) { const uint end = qMin(cursor_ + length - 1, length_ - 1); //tDebug( LOGINFO ) << "#### CloudStream : reading block from " << start << " to " << end << " for " << url_.toString(); - + tDebug( LOGINFO ) << "#### CloudStream : parsing from " << url_.toString(); + tDebug( LOGINFO ) << "#### CloudStream : parsing from (encoded) " << url_.toEncoded().constData(); if (end < start) { return TagLib::ByteVector(); } - if(num_requests_in_error_ > MAX_ALLOW_ERROR_QUERY){ - return TagLib::ByteVector(); - } - if (CheckCache(start, end)) { TagLib::ByteVector cached = GetCached(start, end); cursor_ += cached.size(); return cached; } + if(num_requests_in_error_ > MAX_ALLOW_ERROR_QUERY){ + return TagLib::ByteVector(); + } + + if(refreshUrlEachTime_){ + if(!refreshStreamUrl()){ + tDebug( LOGINFO ) << "#### CloudStream : cannot refresh streamUrl for " << filename_; + } + } + QNetworkRequest request = QNetworkRequest(url_); - //setings of specials OAuth (1 or 2) headers + //setings of specials OAuth (1 or 2) headers foreach(const QString& headerName, headers_.keys()) { request.setRawHeader(headerName.toLocal8Bit(), headers_[headerName].toString().toLocal8Bit()); @@ -163,55 +171,34 @@ TagLib::ByteVector CloudStream::readBlock(ulong length) { reply->deleteLater(); int code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - tDebug() << "######## CloudStream : HTTP reply : "; + tDebug() << "######### CloudStream : HTTP reply : #########"; tDebug( LOGINFO ) << "#### Cloudstream : HttpStatusCode : " << code; foreach (const QNetworkReply::RawHeaderPair& pair, reply->rawHeaderPairs()){ tDebug( LOGINFO ) << "#### Cloudstream : header reply " << pair; } + QByteArray data = reply->readAll(); + if (code != 206) { num_requests_in_error_++; tDebug( LOGINFO ) << "#### Cloudstream : Error " << code << " retrieving url to tag for " << filename_; - if(!javascriptRefreshUrlFunction_.isEmpty()){ - tDebug( LOGINFO ) << "####### Cloudstream : trying to get a good URL for " << fileId_; - QString refreshUrl = QString("resolver.%1( \"%2\" );").arg( javascriptRefreshUrlFunction_ ) - .arg( fileId_ ); - tDebug( LOGINFO ) << refreshUrl; - QVariant response = scriptResolver_->executeJavascript(refreshUrl); - - - if(response.isNull()){ - tDebug( LOGINFO ) << "####### Cloudstream : response is empty, returning" << response; - return TagLib::ByteVector(); - } - QVariantMap request; - if(response.type() == QVariant::Map) - { - request = response.toMap(); - - url_ = QUrl(request["url"].toString()); - - headers_ = request["headers"].toMap(); - } - else - { - url_ = QUrl(response.toString()); - } - - TagLib::ByteVector bytes = readBlock(length); - //if we have datas, let another chance to parse ID3Tags (especially for Dropbox) - if(bytes.size() > 0){ - tDebug( LOGINFO ) << "#### Cloudstream : we have a response !"; - num_requests_in_error_--; - } - return bytes; + tDebug() << "#### CloudStream : body response : " << data; + + if(refreshStreamUrl()) { + TagLib::ByteVector bytes = readBlock(length); + //if we have datas, let another chance to parse ID3Tags (especially for Dropbox) + if(bytes.size() > 0){ + tDebug( LOGINFO ) << "#### Cloudstream : we have datas response with the refreshUrl !"; + num_requests_in_error_--; + } + return bytes; } else { - return TagLib::ByteVector(); + return TagLib::ByteVector(); } } - QByteArray data = reply->readAll(); + TagLib::ByteVector bytes(data.data(), data.size()); cursor_ += data.size(); @@ -219,6 +206,41 @@ TagLib::ByteVector CloudStream::readBlock(ulong length) { return bytes; } +bool CloudStream::refreshStreamUrl() { + if(javascriptRefreshUrlFunction_.isEmpty()){ + return false; + } + tDebug( LOGINFO ) << "####### Cloudstream : refreshing streamUrl for " << filename_; + QString refreshUrl = QString("resolver.%1( \"%2\" );").arg( javascriptRefreshUrlFunction_ ).arg( fileId_ ); + tDebug( LOGINFO ) << "####### Cloudstream : refresh request : " << refreshUrl; + QVariant response = scriptResolver_->executeJavascript(refreshUrl); + + if(response.isNull()){ + tDebug( LOGINFO ) << "####### Cloudstream : refreshUrl response is empty, returning"; + return false; + } + + QVariantMap request; + QString urlString; + + if(response.type() == QVariant::Map) + { + request = response.toMap(); + + urlString = request["url"].toString(); + + headers_ = request["headers"].toMap(); + } + else + { + urlString = response.toString(); + } + + url_.setUrl(urlString); + tDebug( LOGINFO ) << "####### Cloudstream : streamUrl refreshed for " << filename_; + return true; +} + void CloudStream::writeBlock(const TagLib::ByteVector&) { tDebug( LOGINFO ) << "writeBlock not implemented"; } diff --git a/src/libtomahawk/utils/cloudstream.h b/src/libtomahawk/utils/cloudstream.h index 89725ea5c0..6e60ae3343 100644 --- a/src/libtomahawk/utils/cloudstream.h +++ b/src/libtomahawk/utils/cloudstream.h @@ -38,7 +38,10 @@ class CloudStream : public QObject, public TagLib::IOStream { const QString& fileId, const long length, QVariantMap& headers, - QNetworkAccessManager* network, QtScriptResolver *scriptResolver, const QString& javascriptRefreshUrlFunction); + QNetworkAccessManager* network, + QtScriptResolver *scriptResolver, + const QString& javascriptRefreshUrlFunction, + const bool refreshUrlEachTime); //Taglib::IOStream; virtual TagLib::FileName name() const; @@ -69,11 +72,14 @@ class CloudStream : public QObject, public TagLib::IOStream { // Use educated guess to request the bytes that TagLib will probably want. void Precache(); + bool refreshStreamUrl(); + private: bool CheckCache(int start, int end); void FillCache(int start, TagLib::ByteVector data); TagLib::ByteVector GetCached(int start, int end); + private slots: void SSLErrors(const QList& errors); @@ -85,6 +91,7 @@ class CloudStream : public QObject, public TagLib::IOStream { const ulong length_; QVariantMap headers_; const QString javascriptRefreshUrlFunction_; + const bool refreshUrlEachTime_; int cursor_; QNetworkAccessManager* network_; From f052557b8652230c44b83f0118a11e5120e03228 Mon Sep 17 00:00:00 2001 From: loclamor Date: Thu, 28 Mar 2013 14:29:27 +0100 Subject: [PATCH 36/76] Style convention clean-up --- src/libtomahawk/CMakeLists.txt | 2 +- .../resolvers/QtScriptResolver.cpp | 155 ++++---- src/libtomahawk/resolvers/QtScriptResolver.h | 5 +- src/libtomahawk/utils/CloudStream.cpp | 364 ++++++++++++++++++ src/libtomahawk/utils/CloudStream.h | 109 ++++++ src/libtomahawk/utils/cloudstream.cpp | 304 --------------- src/libtomahawk/utils/cloudstream.h | 105 ----- 7 files changed, 543 insertions(+), 501 deletions(-) create mode 100644 src/libtomahawk/utils/CloudStream.cpp create mode 100644 src/libtomahawk/utils/CloudStream.h delete mode 100644 src/libtomahawk/utils/cloudstream.cpp delete mode 100644 src/libtomahawk/utils/cloudstream.h diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 89d760dcc7..13eb7efc42 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -115,7 +115,7 @@ set( libGuiSources utils/SharedTimeLine.cpp utils/WebResultHintChecker.cpp utils/NetworkReply.cpp - utils/cloudstream.cpp + utils/CloudStream.cpp widgets/AnimatedCounterLabel.cpp widgets/BasicHeader.cpp diff --git a/src/libtomahawk/resolvers/QtScriptResolver.cpp b/src/libtomahawk/resolvers/QtScriptResolver.cpp index 372a154667..ddda02f604 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.cpp +++ b/src/libtomahawk/resolvers/QtScriptResolver.cpp @@ -58,9 +58,7 @@ #include //--- includes readcloudFile -//#include "taghandlers/tag.h" -# include "utils/cloudstream.h" - +#include "utils/CloudStream.h" #include #include #include @@ -84,12 +82,8 @@ #include #include #include - #include - #include "qjson/serializer.h" - - //--- end includes readcloudfile // FIXME: bloody hack, remove this for 0.3 @@ -360,8 +354,9 @@ QtScriptResolverHelper::base64Decode( const QByteArray& input ) void -QtScriptResolverHelper::ReadCloudFile(const QString& fileName, const QString& fileId, const QString& sizeS, - const QString& mime_type, const QVariant& requestJS, const QString& javascriptCallbackFunction, +QtScriptResolverHelper::readCloudFile(const QString& fileName, const QString& fileId, + const QString& sizeS, const QString& mime_type, + const QVariant& requestJS, const QString& javascriptCallbackFunction, const QString& javascriptRefreshUrlFunction, const bool refreshUrlEachTime) { @@ -374,7 +369,7 @@ QtScriptResolverHelper::ReadCloudFile(const QString& fileName, const QString& fi QString urlString; - if(requestJS.type() == QVariant::Map) + if ( requestJS.type() == QVariant::Map ) { request = requestJS.toMap(); @@ -387,7 +382,7 @@ QtScriptResolverHelper::ReadCloudFile(const QString& fileName, const QString& fi urlString = requestJS.toString(); } - download_url.setUrl(urlString); + download_url.setUrl( urlString ); tDebug( LOGINFO ) << "#### ReadCloudFile : Loading tags of " << fileName << " from " << download_url.toString() << " which have id " << fileId; @@ -396,101 +391,85 @@ QtScriptResolverHelper::ReadCloudFile(const QString& fileName, const QString& fi m["mimetype"] = mime_type.toUtf8(); - CloudStream* stream = new CloudStream(download_url, fileName, fileId, - size, headers, network, m_resolver, - javascriptRefreshUrlFunction, refreshUrlEachTime); + CloudStream* stream = new CloudStream( download_url, fileName, fileId, + size, headers, network, m_resolver, + javascriptRefreshUrlFunction, refreshUrlEachTime ); stream->Precache(); boost::scoped_ptr tag; - if (mime_type == "audio/mpeg") { // && title.endsWith(".mp3")) { - tag.reset(new TagLib::MPEG::File( - stream, // Takes ownership. - TagLib::ID3v2::FrameFactory::instance(), - TagLib::AudioProperties::Accurate)); - } else if (mime_type == "audio/mp4" || - (mime_type == "audio/mpeg")) { // && title.endsWith(".m4a"))) { - tag.reset(new TagLib::MP4::File( - stream, - true, - TagLib::AudioProperties::Accurate)); - } else if (mime_type == "application/ogg" || - mime_type == "audio/ogg") { - tag.reset(new TagLib::Ogg::Vorbis::File( - stream, - true, - TagLib::AudioProperties::Accurate)); + if ( mime_type == "audio/mpeg" ) // && title.endsWith(".mp3")) + { + tag.reset(new TagLib::MPEG::File( + stream, // Takes ownership. + TagLib::ID3v2::FrameFactory::instance(), + TagLib::AudioProperties::Accurate)); + } + else if ( mime_type == "audio/mp4" || ( mime_type == "audio/mpeg" ) ) // && title.endsWith(".m4a"))) + { + tag.reset( new TagLib::MP4::File( stream, true, TagLib::AudioProperties::Accurate ) ); + } + else if ( mime_type == "application/ogg" || mime_type == "audio/ogg" ) + { + tag.reset(new TagLib::Ogg::Vorbis::File( stream, true, TagLib::AudioProperties::Accurate ) ); + } +#ifdef TAGLIB_HAS_OPUS + else if ( mime_type == "application/opus" || mime_type == "audio/opus" ) + { + tag.reset(new TagLib::Ogg::Opus::File( stream, true, TagLib::AudioProperties::Accurate ) ); + } +#endif + else if ( mime_type == "application/x-flac" || mime_type == "audio/flac" ) + { + tag.reset(new TagLib::FLAC::File( stream, TagLib::ID3v2::FrameFactory::instance(), true, + TagLib::AudioProperties::Accurate ) ); } - #ifdef TAGLIB_HAS_OPUS - else if (mime_type == "application/opus" || - mime_type == "audio/opus") { - tag.reset(new TagLib::Ogg::Opus::File( - stream, - true, - TagLib::AudioProperties::Accurate)); + else if ( mime_type == "audio/x-ms-wma" ) + { + tag.reset( new TagLib::ASF::File( stream, true, TagLib::AudioProperties::Accurate ) ); } - #endif - else if (mime_type == "application/x-flac" || - mime_type == "audio/flac") { - tag.reset(new TagLib::FLAC::File( - stream, - TagLib::ID3v2::FrameFactory::instance(), - true, - TagLib::AudioProperties::Accurate)); - } else if (mime_type == "audio/x-ms-wma") { - tag.reset(new TagLib::ASF::File( - stream, - true, - TagLib::AudioProperties::Accurate)); - } else { - tDebug( LOGINFO ) << "Unknown mime type for tagging:" << mime_type; - //return m; + else + { + tDebug( LOGINFO ) << "Unknown mime type for tagging:" << mime_type; } if (stream->num_requests() > 2) { - // Warn if pre-caching failed. - tDebug( LOGINFO ) << "Total requests for file:" << fileName - << stream->num_requests() - << stream->cached_bytes(); + // Warn if pre-caching failed. + tDebug( LOGINFO ) << "Total requests for file:" << fileName + << " : " << stream->num_requests() << " with " + << stream->cached_bytes() << " bytes cached"; } //construction of the tag's map - if (tag->tag() && !tag->tag()->isEmpty()) { - - m["track"] = tag->tag()->title().toCString(true); - m["artist"] = tag->tag()->artist().toCString(true); - m["album"] = tag->tag()->album().toCString(true); - m["size"] = QString::number(size); - - if (tag->tag()->track() != 0) { - m["albumpos"] = tag->tag()->track(); - } - if (tag->tag()->year() != 0) { - m["year"] = tag->tag()->year(); - } - - if (tag->audioProperties()) { - m["duration"] = tag->audioProperties()->length(); - m["bitrate"] = tag->audioProperties()->bitrate(); - } -/* if (tag->tag()->albumArtist()) { - m["albumartist"] = tag->tag()->albumArtist(); - } - if (tag->tag()->composer()) { - m["composer"] = tag->tag()->composer(); - } - if (tag->tag()->discNumber() != 0) { - m["discnumber"] = tag->tag()->discNumber(); - } -*/ + if ( tag->tag() && !tag->tag()->isEmpty() ) + { + m["track"] = tag->tag()->title().toCString( true ); + m["artist"] = tag->tag()->artist().toCString( true ); + m["album"] = tag->tag()->album().toCString( true ); + m["size"] = QString::number( size ); + + if ( tag->tag()->track() != 0 ) + { + m["albumpos"] = tag->tag()->track(); + } + if ( tag->tag()->year() != 0 ) + { + m["year"] = tag->tag()->year(); + } + + if ( tag->audioProperties() ) + { + m["duration"] = tag->audioProperties()->length(); + m["bitrate"] = tag->audioProperties()->bitrate(); + } } QJson::Serializer serializer; - QByteArray json = serializer.serialize(m); + QByteArray json = serializer.serialize( m ); tDebug() << "#### ReadCloudFile : Sending tags to js : " << json; QString getUrl = QString( "Tomahawk.resolver.instance.%1( %2 );" ).arg( javascriptCallbackFunction ) - .arg( QString(json) ); + .arg( QString(json) ); m_resolver->m_engine->mainFrame()->evaluateJavaScript( getUrl ); } diff --git a/src/libtomahawk/resolvers/QtScriptResolver.h b/src/libtomahawk/resolvers/QtScriptResolver.h index d9b2014e54..2ad3530365 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.h +++ b/src/libtomahawk/resolvers/QtScriptResolver.h @@ -66,10 +66,9 @@ Q_OBJECT // send ID3Tags of the stream as argument of the callback function - Q_INVOKABLE void - ReadCloudFile(const QString& fileName, const QString& fileId, const QString& sizeS, + Q_INVOKABLE void readCloudFile( const QString& fileName, const QString& fileId, const QString& sizeS, const QString& mime_type, const QVariant& requestJS, const QString& javascriptCallbackFunction, - const QString& javascriptRefreshUrlFunction = QString(), const bool refreshUrlEachTime = false); + const QString& javascriptRefreshUrlFunction = QString(), const bool refreshUrlEachTime = false ); Q_INVOKABLE void addLocalJSFile(const QString& jsFilePath); diff --git a/src/libtomahawk/utils/CloudStream.cpp b/src/libtomahawk/utils/CloudStream.cpp new file mode 100644 index 0000000000..16122e4ee6 --- /dev/null +++ b/src/libtomahawk/utils/CloudStream.cpp @@ -0,0 +1,364 @@ +/* This file is part of Clementine. + Copyright 2012, David Sansome + + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Clementine is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Clementine. If not, see . +*/ + +#include "CloudStream.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "utils/Logger.h" + +#include "resolvers/QtScriptResolver.h" + +namespace +{ + static const int kTaglibPrefixCacheBytes = 64 * 1024; // Should be enough. + static const int kTaglibSuffixCacheBytes = 8 * 1024; +} + +const static int MAX_ALLOW_ERROR_QUERY = 2; + +CloudStream::CloudStream( QUrl& url, + const QString& filename, + const QString& fileId, + const long length, + QVariantMap& headers, + QNetworkAccessManager* network, + QtScriptResolver* scriptResolver, + const QString & javascriptRefreshUrlFunction, + const bool refreshUrlEachTime ) + : m_url( url ) + , m_filename( filename ) + , m_fileId( fileId ) + , m_encoded_filename( m_filename.toUtf8() ) + , m_length( length ) + , m_headers( headers ) + , m_cursor( 0 ) + , m_network( network ) + , m_cache( length ) + , m_num_requests( 0 ) + , m_num_requests_in_error( 0 ) + , m_scriptResolver( scriptResolver ) + , m_javascriptRefreshUrlFunction( javascriptRefreshUrlFunction ) + , m_refreshUrlEachTime( refreshUrlEachTime ) +{ + tDebug( LOGINFO ) << "#### Cloudstream : CloudStream object created for " << m_filename << " : " + << m_url.toString(); +} + +TagLib::FileName +CloudStream::name() const +{ + return m_encoded_filename.data(); +} + +bool +CloudStream::CheckCache( int start, int end ) +{ + for ( int i = start; i <= end; ++i ) { + if ( !m_cache.test( i ) ) { + return false; + } + } + return true; +} + +void +CloudStream::FillCache( int start, TagLib::ByteVector data ) +{ + for ( int i = 0; i < data.size(); ++i ) + { + m_cache.set( start + i, data[i] ); + } +} + +TagLib::ByteVector +CloudStream::GetCached( int start, int end ) +{ + const uint size = end - start + 1; + TagLib::ByteVector ret( size ); + for ( int i = 0; i < size; ++i ) + { + ret[i] = m_cache.get( start + i ); + } + return ret; +} + +void +CloudStream::Precache() +{ + // For reading the tags of an MP3, TagLib tends to request: + // 1. The first 1024 bytes + // 2. Somewhere between the first 2KB and first 60KB + // 3. The last KB or two. + // 4. Somewhere in the first 64KB again + // + // OGG Vorbis may read the last 4KB. + // + // So, if we precache the first 64KB and the last 8KB we should be sorted :-) + // Ideally, we would use bytes=0-655364,-8096 but Google Drive does not seem + // to support multipart byte ranges yet so we have to make do with two + // requests. + tDebug( LOGINFO ) << "#### CloudStream : Precaching from :" << m_filename; + seek( 0, TagLib::IOStream::Beginning ); + readBlock( kTaglibPrefixCacheBytes ); + seek( kTaglibSuffixCacheBytes, TagLib::IOStream::End ); + readBlock( kTaglibSuffixCacheBytes ); + clear(); + tDebug( LOGINFO ) << "#### CloudStream : Precaching end for :" << m_filename; +} + +TagLib::ByteVector +CloudStream::readBlock( ulong length ) +{ + + const uint start = m_cursor; + const uint end = qMin( m_cursor + length - 1, m_length - 1 ); + + tDebug( LOGINFO ) << "#### CloudStream : parsing from " << m_url.toString(); + tDebug( LOGINFO ) << "#### CloudStream : parsing from (encoded) " << m_url.toEncoded().constData(); + if ( end < start ) + { + return TagLib::ByteVector(); + } + + if ( CheckCache( start, end ) ) + { + TagLib::ByteVector cached = GetCached( start, end ); + m_cursor += cached.size(); + return cached; + } + + if ( m_num_requests_in_error > MAX_ALLOW_ERROR_QUERY ) + { + return TagLib::ByteVector(); + } + + if ( m_refreshUrlEachTime ) + { + if( !refreshStreamUrl() ) + { + tDebug( LOGINFO ) << "#### CloudStream : cannot refresh streamUrl for " << m_filename; + } + } + + QNetworkRequest request = QNetworkRequest( m_url ); + + //setings of specials OAuth (1 or 2) headers + foreach ( const QString& headerName, m_headers.keys() ) + { + request.setRawHeader( headerName.toLocal8Bit(), m_headers[headerName].toString().toLocal8Bit() ); + + } + + request.setRawHeader( "Range", QString( "bytes=%1-%2" ).arg( start ).arg( end ).toUtf8() ); + request.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork ); + // The Ubuntu One server applies the byte range to the gzipped data, rather + // than the raw data so we must disable compression. + if ( m_url.host() == "files.one.ubuntu.com" ) + { + request.setRawHeader( "Accept-Encoding", "identity" ); + } + + //tDebug() << request.rawHeader("Authorization"); + tDebug() << "######## CloudStream : HTTP request : "; + foreach ( const QByteArray& header, request.rawHeaderList() ) + { + tDebug() << "#### CloudStream : header request : " << header << " = " << request.rawHeader(header); + } + + QNetworkReply* reply = m_network->get( request ); + connect( reply, SIGNAL( sslErrors( QList ) ), SLOT( SSLErrors( QList ) ) ); + ++m_num_requests; + + QEventLoop loop; + QObject::connect( reply, SIGNAL( finished() ), &loop, SLOT( quit() ) ); + loop.exec(); + reply->deleteLater(); + + int code = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt(); + tDebug() << "######### CloudStream : HTTP reply : #########"; + tDebug( LOGINFO ) << "#### Cloudstream : HttpStatusCode : " << code; + foreach ( const QNetworkReply::RawHeaderPair& pair, reply->rawHeaderPairs() ) + { + tDebug( LOGINFO ) << "#### Cloudstream : header reply " << pair; + } + + QByteArray data = reply->readAll(); + + if ( code != 206 ) + { + m_num_requests_in_error++; + tDebug( LOGINFO ) << "#### Cloudstream : Error " << code << " retrieving url to tag for " << m_filename; + tDebug() << "#### CloudStream : body response : " << data; + + if ( refreshStreamUrl() ) + { + TagLib::ByteVector bytes = readBlock( length ); + //if we have datas, let another chance to parse ID3Tags (especially for Dropbox) + if( bytes.size() > 0 ){ + tDebug( LOGINFO ) << "#### Cloudstream : we have datas response with the refreshUrl !"; + m_num_requests_in_error--; + } + return bytes; + } + else + { + return TagLib::ByteVector(); + } + } + + + TagLib::ByteVector bytes( data.data(), data.size() ); + m_cursor += data.size(); + + FillCache( start, bytes ); + return bytes; +} + +bool +CloudStream::refreshStreamUrl() +{ + if ( m_javascriptRefreshUrlFunction.isEmpty() ) + { + return false; + } + tDebug( LOGINFO ) << "####### Cloudstream : refreshing streamUrl for " << m_filename; + QString refreshUrl = QString( "resolver.%1( \"%2\" );" ).arg( m_javascriptRefreshUrlFunction ) + .arg( m_fileId ); + tDebug( LOGINFO ) << "####### Cloudstream : refresh request : " << refreshUrl; + QVariant response = m_scriptResolver->executeJavascript( refreshUrl ); + + if ( response.isNull() ) + { + tDebug( LOGINFO ) << "####### Cloudstream : refreshUrl response is empty, returning"; + return false; + } + + QVariantMap request; + QString urlString; + + if ( response.type() == QVariant::Map ) + { + request = response.toMap(); + + urlString = request["url"].toString(); + + m_headers = request["headers"].toMap(); + } + else + { + urlString = response.toString(); + } + + m_url.setUrl( urlString ); + tDebug( LOGINFO ) << "####### Cloudstream : streamUrl refreshed for " << m_filename; + return true; +} + +void +CloudStream::writeBlock( const TagLib::ByteVector& ) +{ + tDebug( LOGINFO ) << "writeBlock not implemented"; +} + +void +CloudStream::insert( const TagLib::ByteVector&, ulong, ulong ) +{ + tDebug( LOGINFO ) << "insert not implemented"; +} + +void +CloudStream::removeBlock( ulong, ulong ) +{ + tDebug( LOGINFO ) << "removeBlock not implemented"; +} + +bool +CloudStream::readOnly() const +{ + tDebug( LOGINFO ) << "readOnly not implemented"; + return true; +} + +bool +CloudStream::isOpen() const +{ + return true; +} + +void +CloudStream::seek( long offset, TagLib::IOStream::Position p ) +{ + switch ( p ) + { + case TagLib::IOStream::Beginning: + m_cursor = offset; + break; + + case TagLib::IOStream::Current: + m_cursor = qMin( ulong( m_cursor + offset ), m_length ); + break; + + case TagLib::IOStream::End: + // This should really not have qAbs(), but OGG reading needs it. + m_cursor = qMax( 0UL, m_length - qAbs( offset ) ); + break; + } +} + +void +CloudStream::clear() +{ + m_cursor = 0; +} + +long +CloudStream::tell() const +{ + return m_cursor; +} + +long +CloudStream::length() +{ + return m_length; +} + +void +CloudStream::truncate( long ) +{ + tDebug( LOGINFO ) << "not implemented"; +} + +void +CloudStream::SSLErrors( const QList& errors ) +{ + foreach ( const QSslError& error, errors ) + { + tDebug( LOGINFO ) << "#### Cloudstream : Error for " << m_filename << " : "; + tDebug( LOGINFO ) << error.error() << error.errorString(); + tDebug( LOGINFO ) << error.certificate(); + } +} diff --git a/src/libtomahawk/utils/CloudStream.h b/src/libtomahawk/utils/CloudStream.h new file mode 100644 index 0000000000..57ae132b9b --- /dev/null +++ b/src/libtomahawk/utils/CloudStream.h @@ -0,0 +1,109 @@ +/* This file is part of Clementine. + Copyright 2012, David Sansome + + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Clementine is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Clementine. If not, see . +*/ + +//#ifndef GOOGLEDRIVESTREAM_H +//#define GOOGLEDRIVESTREAM_H + +#include +#include +#include +#include + + +#include +#include + +class QNetworkAccessManager; +class QtScriptResolver; + +class CloudStream : public QObject, public TagLib::IOStream +{ + Q_OBJECT +public: + CloudStream( QUrl& url, + const QString& filename, + const QString& fileId, + const long length, + QVariantMap& headers, + QNetworkAccessManager* network, + QtScriptResolver *scriptResolver, + const QString& javascriptRefreshUrlFunction, + const bool refreshUrlEachTime ); + + //Taglib::IOStream; + virtual TagLib::FileName name() const; + virtual TagLib::ByteVector readBlock( ulong length ); + virtual void writeBlock( const TagLib::ByteVector& ); + virtual void insert( const TagLib::ByteVector&, ulong, ulong ); + virtual void removeBlock( ulong, ulong ); + virtual bool readOnly() const; + virtual bool isOpen() const; + virtual void seek( long offset, TagLib::IOStream::Position p ); + virtual void clear(); + virtual long tell() const; + virtual long length(); + virtual void truncate( long ); + + google::sparsetable::size_type cached_bytes() const + { + return m_cache.num_nonempty(); + } + + int num_requests() const + { + return m_num_requests; + } + + int num_requests_in_error() const + { + return m_num_requests_in_error; + } + + // Use educated guess to request the bytes that TagLib will probably want. + void Precache(); + + bool refreshStreamUrl(); + +private: + bool CheckCache( int start, int end ); + void FillCache( int start, TagLib::ByteVector data ); + TagLib::ByteVector GetCached( int start, int end ); + + +private slots: + void SSLErrors( const QList& errors ); + +private: + QUrl m_url; + const QString m_filename; + const QString m_fileId; + const QByteArray m_encoded_filename; + const ulong m_length; + QVariantMap m_headers; + const QString m_javascriptRefreshUrlFunction; + const bool m_refreshUrlEachTime; + + int m_cursor; + QNetworkAccessManager* m_network; + QtScriptResolver* m_scriptResolver; + + google::sparsetable m_cache; + int m_num_requests; + int m_num_requests_in_error; +}; + +//#endif // GOOGLEDRIVESTREAM_H diff --git a/src/libtomahawk/utils/cloudstream.cpp b/src/libtomahawk/utils/cloudstream.cpp deleted file mode 100644 index 639ca17b6f..0000000000 --- a/src/libtomahawk/utils/cloudstream.cpp +++ /dev/null @@ -1,304 +0,0 @@ -/* This file is part of Clementine. - Copyright 2012, David Sansome - - Clementine is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Clementine is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Clementine. If not, see . -*/ - -#include "cloudstream.h" - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "utils/Logger.h" - -#include "resolvers/QtScriptResolver.h" - -namespace { - static const int kTaglibPrefixCacheBytes = 64 * 1024; // Should be enough. - static const int kTaglibSuffixCacheBytes = 8 * 1024; -} - -const static int MAX_ALLOW_ERROR_QUERY = 2; - -CloudStream::CloudStream( - QUrl& url, const QString& filename, const QString& fileId, const long length, - QVariantMap& headers, QNetworkAccessManager* network, QtScriptResolver* scriptResolver, - const QString & javascriptRefreshUrlFunction, const bool refreshUrlEachTime) - : url_(url), - filename_(filename), - fileId_(fileId), - encoded_filename_(filename_.toUtf8()), - length_(length), - headers_(headers), - cursor_(0), - network_(network), - cache_(length), - num_requests_(0), - num_requests_in_error_(0), - scriptResolver_(scriptResolver), - javascriptRefreshUrlFunction_(javascriptRefreshUrlFunction), - refreshUrlEachTime_(refreshUrlEachTime){ - tDebug( LOGINFO ) << "#### Cloudstream : CloudStream object created for " << filename_ << " : " << url_.toString(); -} - -TagLib::FileName CloudStream::name() const { - return encoded_filename_.data(); -} - -bool CloudStream::CheckCache(int start, int end) { - for (int i = start; i <= end; ++i) { - if (!cache_.test(i)) { - return false; - } - } - return true; -} - -void CloudStream::FillCache(int start, TagLib::ByteVector data) { - for (int i = 0; i < data.size(); ++i) { - cache_.set(start + i, data[i]); - } -} - -TagLib::ByteVector CloudStream::GetCached(int start, int end) { - const uint size = end - start + 1; - TagLib::ByteVector ret(size); - for (int i = 0; i < size; ++i) { - ret[i] = cache_.get(start + i); - } - return ret; -} - -void CloudStream::Precache() { - // For reading the tags of an MP3, TagLib tends to request: - // 1. The first 1024 bytes - // 2. Somewhere between the first 2KB and first 60KB - // 3. The last KB or two. - // 4. Somewhere in the first 64KB again - // - // OGG Vorbis may read the last 4KB. - // - // So, if we precache the first 64KB and the last 8KB we should be sorted :-) - // Ideally, we would use bytes=0-655364,-8096 but Google Drive does not seem - // to support multipart byte ranges yet so we have to make do with two - // requests. - tDebug( LOGINFO ) << "#### CloudStream : Precaching from :" << filename_; - seek(0, TagLib::IOStream::Beginning); - readBlock(kTaglibPrefixCacheBytes); - seek(kTaglibSuffixCacheBytes, TagLib::IOStream::End); - readBlock(kTaglibSuffixCacheBytes); - clear(); - tDebug( LOGINFO ) << "#### CloudStream : Precaching end for :" << filename_; -} - -TagLib::ByteVector CloudStream::readBlock(ulong length) { - - const uint start = cursor_; - const uint end = qMin(cursor_ + length - 1, length_ - 1); - - //tDebug( LOGINFO ) << "#### CloudStream : reading block from " << start << " to " << end << " for " << url_.toString(); - tDebug( LOGINFO ) << "#### CloudStream : parsing from " << url_.toString(); - tDebug( LOGINFO ) << "#### CloudStream : parsing from (encoded) " << url_.toEncoded().constData(); - if (end < start) { - return TagLib::ByteVector(); - } - - if (CheckCache(start, end)) { - TagLib::ByteVector cached = GetCached(start, end); - cursor_ += cached.size(); - return cached; - } - - if(num_requests_in_error_ > MAX_ALLOW_ERROR_QUERY){ - return TagLib::ByteVector(); - } - - if(refreshUrlEachTime_){ - if(!refreshStreamUrl()){ - tDebug( LOGINFO ) << "#### CloudStream : cannot refresh streamUrl for " << filename_; - } - } - - QNetworkRequest request = QNetworkRequest(url_); - - //setings of specials OAuth (1 or 2) headers - foreach(const QString& headerName, headers_.keys()) { - request.setRawHeader(headerName.toLocal8Bit(), headers_[headerName].toString().toLocal8Bit()); - - } - - request.setRawHeader( - "Range", QString("bytes=%1-%2").arg(start).arg(end).toUtf8()); - request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, - QNetworkRequest::AlwaysNetwork); - // The Ubuntu One server applies the byte range to the gzipped data, rather - // than the raw data so we must disable compression. - if (url_.host() == "files.one.ubuntu.com") { - request.setRawHeader("Accept-Encoding", "identity"); - } - - //tDebug() << request.rawHeader("Authorization"); - tDebug() << "######## CloudStream : HTTP request : "; - foreach(const QByteArray& header, request.rawHeaderList()){ - tDebug() << "#### CloudStream : header request : " << header << " = " << request.rawHeader(header); - } - - QNetworkReply* reply = network_->get(request); - connect(reply, SIGNAL(sslErrors(QList)), SLOT(SSLErrors(QList))); - ++num_requests_; - - QEventLoop loop; - QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); - loop.exec(); - reply->deleteLater(); - - int code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - tDebug() << "######### CloudStream : HTTP reply : #########"; - tDebug( LOGINFO ) << "#### Cloudstream : HttpStatusCode : " << code; - foreach (const QNetworkReply::RawHeaderPair& pair, reply->rawHeaderPairs()){ - tDebug( LOGINFO ) << "#### Cloudstream : header reply " << pair; - } - - QByteArray data = reply->readAll(); - - if (code != 206) { - num_requests_in_error_++; - tDebug( LOGINFO ) << "#### Cloudstream : Error " << code << " retrieving url to tag for " << filename_; - tDebug() << "#### CloudStream : body response : " << data; - - if(refreshStreamUrl()) { - TagLib::ByteVector bytes = readBlock(length); - //if we have datas, let another chance to parse ID3Tags (especially for Dropbox) - if(bytes.size() > 0){ - tDebug( LOGINFO ) << "#### Cloudstream : we have datas response with the refreshUrl !"; - num_requests_in_error_--; - } - return bytes; - } - else { - return TagLib::ByteVector(); - } - } - - - TagLib::ByteVector bytes(data.data(), data.size()); - cursor_ += data.size(); - - FillCache(start, bytes); - return bytes; -} - -bool CloudStream::refreshStreamUrl() { - if(javascriptRefreshUrlFunction_.isEmpty()){ - return false; - } - tDebug( LOGINFO ) << "####### Cloudstream : refreshing streamUrl for " << filename_; - QString refreshUrl = QString("resolver.%1( \"%2\" );").arg( javascriptRefreshUrlFunction_ ).arg( fileId_ ); - tDebug( LOGINFO ) << "####### Cloudstream : refresh request : " << refreshUrl; - QVariant response = scriptResolver_->executeJavascript(refreshUrl); - - if(response.isNull()){ - tDebug( LOGINFO ) << "####### Cloudstream : refreshUrl response is empty, returning"; - return false; - } - - QVariantMap request; - QString urlString; - - if(response.type() == QVariant::Map) - { - request = response.toMap(); - - urlString = request["url"].toString(); - - headers_ = request["headers"].toMap(); - } - else - { - urlString = response.toString(); - } - - url_.setUrl(urlString); - tDebug( LOGINFO ) << "####### Cloudstream : streamUrl refreshed for " << filename_; - return true; -} - -void CloudStream::writeBlock(const TagLib::ByteVector&) { - tDebug( LOGINFO ) << "writeBlock not implemented"; -} - -void CloudStream::insert(const TagLib::ByteVector&, ulong, ulong) { - tDebug( LOGINFO ) << "insert not implemented"; -} - -void CloudStream::removeBlock(ulong, ulong) { - tDebug( LOGINFO ) << "removeBlock not implemented"; -} - -bool CloudStream::readOnly() const { - tDebug( LOGINFO ) << "readOnly not implemented"; - return true; -} - -bool CloudStream::isOpen() const { - return true; -} - -void CloudStream::seek(long offset, TagLib::IOStream::Position p) { - switch (p) { - case TagLib::IOStream::Beginning: - cursor_ = offset; - break; - - case TagLib::IOStream::Current: - cursor_ = qMin(ulong(cursor_ + offset), length_); - break; - - case TagLib::IOStream::End: - // This should really not have qAbs(), but OGG reading needs it. - cursor_ = qMax(0UL, length_ - qAbs(offset)); - break; - } -} - -void CloudStream::clear() { - cursor_ = 0; -} - -long CloudStream::tell() const { - return cursor_; -} - -long CloudStream::length() { - return length_; -} - -void CloudStream::truncate(long) { - tDebug( LOGINFO ) << "not implemented"; -} - -void CloudStream::SSLErrors(const QList& errors) { - foreach (const QSslError& error, errors) { - tDebug( LOGINFO ) << "#### Cloudstream : Error for " << filename_ << " : "; - tDebug( LOGINFO ) << error.error() << error.errorString(); - tDebug( LOGINFO ) << error.certificate(); - } -} diff --git a/src/libtomahawk/utils/cloudstream.h b/src/libtomahawk/utils/cloudstream.h deleted file mode 100644 index 6e60ae3343..0000000000 --- a/src/libtomahawk/utils/cloudstream.h +++ /dev/null @@ -1,105 +0,0 @@ -/* This file is part of Clementine. - Copyright 2012, David Sansome - - Clementine is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Clementine is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Clementine. If not, see . -*/ - -//#ifndef GOOGLEDRIVESTREAM_H -//#define GOOGLEDRIVESTREAM_H - -#include -#include -#include -#include - - -#include -#include - -class QNetworkAccessManager; -class QtScriptResolver; - -class CloudStream : public QObject, public TagLib::IOStream { - Q_OBJECT - public: - CloudStream(QUrl& url, - const QString& filename, - const QString& fileId, - const long length, - QVariantMap& headers, - QNetworkAccessManager* network, - QtScriptResolver *scriptResolver, - const QString& javascriptRefreshUrlFunction, - const bool refreshUrlEachTime); - - //Taglib::IOStream; - virtual TagLib::FileName name() const; - virtual TagLib::ByteVector readBlock(ulong length); - virtual void writeBlock(const TagLib::ByteVector&); - virtual void insert(const TagLib::ByteVector&, ulong, ulong); - virtual void removeBlock(ulong, ulong); - virtual bool readOnly() const; - virtual bool isOpen() const; - virtual void seek(long offset, TagLib::IOStream::Position p); - virtual void clear(); - virtual long tell() const; - virtual long length(); - virtual void truncate(long); - - google::sparsetable::size_type cached_bytes() const { - return cache_.num_nonempty(); - } - - int num_requests() const { - return num_requests_; - } - - int num_requests_in_error() const { - return num_requests_in_error_; - } - - // Use educated guess to request the bytes that TagLib will probably want. - void Precache(); - - bool refreshStreamUrl(); - - private: - bool CheckCache(int start, int end); - void FillCache(int start, TagLib::ByteVector data); - TagLib::ByteVector GetCached(int start, int end); - - - private slots: - void SSLErrors(const QList& errors); - - private: - QUrl url_; - const QString filename_; - const QString fileId_; - const QByteArray encoded_filename_; - const ulong length_; - QVariantMap headers_; - const QString javascriptRefreshUrlFunction_; - const bool refreshUrlEachTime_; - - int cursor_; - QNetworkAccessManager* network_; - QtScriptResolver* scriptResolver_; - - google::sparsetable cache_; - int num_requests_; - int num_requests_in_error_; -}; - -//#endif // GOOGLEDRIVESTREAM_H From 5dcf3526e32e256ee25df9296d369d6a3ac27113 Mon Sep 17 00:00:00 2001 From: Teo Mrnjavac Date: Sun, 10 Mar 2013 13:02:14 +0100 Subject: [PATCH 37/76] Initial commit for resolver bundles: proof of concept. --- src/SettingsDialog.cpp | 41 +++++++++++++++++++++++-- src/libtomahawk/utils/TomahawkUtils.cpp | 12 +++++--- src/libtomahawk/utils/TomahawkUtils.h | 2 +- 3 files changed, 46 insertions(+), 9 deletions(-) diff --git a/src/SettingsDialog.cpp b/src/SettingsDialog.cpp index c3a1bc0cf3..cc2bcabee7 100644 --- a/src/SettingsDialog.cpp +++ b/src/SettingsDialog.cpp @@ -451,16 +451,51 @@ SettingsDialog::openAccountConfig( Account* account, bool showDelete ) void SettingsDialog::installFromFile() { - const QString resolver = QFileDialog::getOpenFileName( 0, tr( "Install resolver from file" ), TomahawkSettings::instance()->scriptDefaultPath() ); + QString resolver = QFileDialog::getOpenFileName( 0, tr( "Install resolver from file" ), + TomahawkSettings::instance()->scriptDefaultPath(), + tr( "Tomahawk Resolvers (*.axe *.js);;" + "All files (*)" ), + 0, + QFileDialog::ReadOnly ); if( !resolver.isEmpty() ) { - const QFileInfo resolverAbsoluteFilePath( resolver ); + //I'm still a little proof of concept, refactor me into a proper class + QFileInfo resolverAbsoluteFilePath( resolver ); TomahawkSettings::instance()->setScriptDefaultPath( resolverAbsoluteFilePath.absolutePath() ); + if ( resolverAbsoluteFilePath.suffix() == "axe" ) + { + QDir dir( TomahawkUtils::extractScriptPayload( resolverAbsoluteFilePath.filePath(), + resolverAbsoluteFilePath.baseName(), + "manualresolvers" ) ); + dir.cd( "content" ); + QFile desktopFile( dir.absoluteFilePath( "metadata.desktop" ) ); + if ( desktopFile.open( QIODevice::ReadOnly | QIODevice::Text ) ) + { + QTextStream desktopFileStream( &desktopFile ); + + while ( !desktopFileStream.atEnd() ) + { + QString line = desktopFileStream.readLine().trimmed(); + //TODO: correct baseName + if ( line.startsWith( "X-Synchrotron-MainScript" ) ) + { + line.remove( QRegExp( "^X-Synchrotron-MainScript\\s*=\\s*" ) ); + resolver = dir.absoluteFilePath( line ); //this is our path to the JS + } + } + } + } + resolverAbsoluteFilePath = QFileInfo( resolver ); + + //TODO: if the new path has a metadata file in the dir structure, read it, check the config + // and act accordingly for multi-account resolvers + + if ( resolverAbsoluteFilePath.baseName() == "spotify_tomahawkresolver" ) { - // HACK if this is a spotify resolver, we treat is specially. + // HACK if this is a spotify resolver, we treat it specially. // usually we expect the user to just download the spotify resolver from attica, // however developers, those who build their own tomahawk, can't do that, or linux // users can't do that. However, we have an already-existing SpotifyAccount that we diff --git a/src/libtomahawk/utils/TomahawkUtils.cpp b/src/libtomahawk/utils/TomahawkUtils.cpp index bc72b10b87..bec74cd258 100644 --- a/src/libtomahawk/utils/TomahawkUtils.cpp +++ b/src/libtomahawk/utils/TomahawkUtils.cpp @@ -911,16 +911,17 @@ verifyFile( const QString& filePath, const QString& signature ) QString -extractScriptPayload( const QString& filename, const QString& resolverId ) +extractScriptPayload( const QString& filename, const QString& resolverId, const QString& dirName ) { // uses QuaZip to extract the temporary zip file to the user's tomahawk data/resolvers directory QDir resolverDir = appDataDir(); - if ( !resolverDir.mkpath( QString( "atticaresolvers/%1" ).arg( resolverId ) ) ) + if ( !resolverDir.mkpath( QString( "%1/%2" ).arg( dirName ) + .arg( resolverId ) ) ) { - tLog() << "Failed to mkdir resolver save dir:" << TomahawkUtils::appDataDir().absoluteFilePath( QString( "atticaresolvers/%1" ).arg( resolverId ) ); + tLog() << "Failed to mkdir resolver save dir:" << TomahawkUtils::appDataDir().absoluteFilePath( QString( "%1/%2" ).arg( dirName ).arg( resolverId ) ); return QString(); } - resolverDir.cd( QString( "atticaresolvers/%1" ).arg( resolverId ) ); + resolverDir.cd( QString( "%1/%2" ).arg( dirName ).arg( resolverId ) ); if ( !unzipFileInFolder( filename, resolverDir ) ) { @@ -941,7 +942,8 @@ unzipFileInFolder( const QString& zipFileName, const QDir& folder ) QuaZip zipFile( zipFileName ); if ( !zipFile.open( QuaZip::mdUnzip ) ) { - qWarning() << "Failed to QuaZip open:" << zipFile.getZipError(); + qWarning() << "Failed to QuaZip open" << zipFileName + << "with error:" << zipFile.getZipError(); return false; } diff --git a/src/libtomahawk/utils/TomahawkUtils.h b/src/libtomahawk/utils/TomahawkUtils.h index 3546777105..70814a6e71 100644 --- a/src/libtomahawk/utils/TomahawkUtils.h +++ b/src/libtomahawk/utils/TomahawkUtils.h @@ -194,7 +194,7 @@ namespace TomahawkUtils DLLEXPORT bool isLocalResult( const QString& url ); DLLEXPORT bool verifyFile( const QString& filePath, const QString& signature ); - DLLEXPORT QString extractScriptPayload( const QString& filename, const QString& resolverId ); + DLLEXPORT QString extractScriptPayload( const QString& filename, const QString& resolverId, const QString& dirName = "atticaresolvers" ); DLLEXPORT bool unzipFileInFolder( const QString& zipFileName, const QDir& folder ); // Extracting may be asynchronous, pass in a receiver object with the following slots: From c7983d1c3505477503c6024ed2928c7f16d9c8f9 Mon Sep 17 00:00:00 2001 From: Teo Mrnjavac Date: Mon, 11 Mar 2013 22:53:58 +0100 Subject: [PATCH 38/76] Found a better place to do bundle loading, and also load metadata. --- src/SettingsDialog.cpp | 44 ++------- src/libtomahawk/accounts/Account.h | 2 + src/libtomahawk/accounts/AccountDelegate.cpp | 9 +- src/libtomahawk/accounts/AccountModel.cpp | 6 +- src/libtomahawk/accounts/ResolverAccount.cpp | 99 +++++++++++++++++++- src/libtomahawk/accounts/ResolverAccount.h | 8 +- 6 files changed, 121 insertions(+), 47 deletions(-) diff --git a/src/SettingsDialog.cpp b/src/SettingsDialog.cpp index cc2bcabee7..4e86932301 100644 --- a/src/SettingsDialog.cpp +++ b/src/SettingsDialog.cpp @@ -451,48 +451,18 @@ SettingsDialog::openAccountConfig( Account* account, bool showDelete ) void SettingsDialog::installFromFile() { - QString resolver = QFileDialog::getOpenFileName( 0, tr( "Install resolver from file" ), - TomahawkSettings::instance()->scriptDefaultPath(), - tr( "Tomahawk Resolvers (*.axe *.js);;" - "All files (*)" ), - 0, - QFileDialog::ReadOnly ); + const QString resolver = QFileDialog::getOpenFileName( 0, tr( "Install resolver from file" ), + TomahawkSettings::instance()->scriptDefaultPath(), + tr( "Tomahawk Resolvers (*.axe *.js);;" + "All files (*)" ), + 0, + QFileDialog::ReadOnly ); if( !resolver.isEmpty() ) { - //I'm still a little proof of concept, refactor me into a proper class - QFileInfo resolverAbsoluteFilePath( resolver ); + const QFileInfo resolverAbsoluteFilePath( resolver ); TomahawkSettings::instance()->setScriptDefaultPath( resolverAbsoluteFilePath.absolutePath() ); - if ( resolverAbsoluteFilePath.suffix() == "axe" ) - { - QDir dir( TomahawkUtils::extractScriptPayload( resolverAbsoluteFilePath.filePath(), - resolverAbsoluteFilePath.baseName(), - "manualresolvers" ) ); - dir.cd( "content" ); - QFile desktopFile( dir.absoluteFilePath( "metadata.desktop" ) ); - if ( desktopFile.open( QIODevice::ReadOnly | QIODevice::Text ) ) - { - QTextStream desktopFileStream( &desktopFile ); - - while ( !desktopFileStream.atEnd() ) - { - QString line = desktopFileStream.readLine().trimmed(); - //TODO: correct baseName - if ( line.startsWith( "X-Synchrotron-MainScript" ) ) - { - line.remove( QRegExp( "^X-Synchrotron-MainScript\\s*=\\s*" ) ); - resolver = dir.absoluteFilePath( line ); //this is our path to the JS - } - } - } - } - resolverAbsoluteFilePath = QFileInfo( resolver ); - - //TODO: if the new path has a metadata file in the dir structure, read it, check the config - // and act accordingly for multi-account resolvers - - if ( resolverAbsoluteFilePath.baseName() == "spotify_tomahawkresolver" ) { // HACK if this is a spotify resolver, we treat it specially. diff --git a/src/libtomahawk/accounts/Account.h b/src/libtomahawk/accounts/Account.h index 324a767793..54b6db6eca 100644 --- a/src/libtomahawk/accounts/Account.h +++ b/src/libtomahawk/accounts/Account.h @@ -88,6 +88,8 @@ class DLLEXPORT Account : public QObject virtual QWidget* aclWidget() = 0; virtual QPixmap icon() const = 0; #endif + virtual QString description() const { return QString(); } + virtual QString author() const { return QString(); } virtual void saveConfig() {} // called when the widget has been edited. save values from config widget, call sync() to write to disk account generic settings diff --git a/src/libtomahawk/accounts/AccountDelegate.cpp b/src/libtomahawk/accounts/AccountDelegate.cpp index 2786e33d2a..2ca7d3e1ed 100644 --- a/src/libtomahawk/accounts/AccountDelegate.cpp +++ b/src/libtomahawk/accounts/AccountDelegate.cpp @@ -278,11 +278,16 @@ AccountDelegate::paint ( QPainter* painter, const QStyleOptionViewItem& option, // Draw the title and description // title QString title = index.data( Qt::DisplayRole ).toString(); + QString author = index.data( AccountModel::AuthorRole ).toString(); + QString desc = index.data( AccountModel::DescriptionRole ).toString(); + const int rightTitleEdge = rightEdge - PADDING; const int leftTitleEdge = pixmapRect.right() + PADDING; painter->setFont( titleFont ); QRect textRect; - const bool canRate = index.data( AccountModel::CanRateRole ).toBool(); + const bool canRate = index.data( AccountModel::CanRateRole ).toBool() + || !author.isEmpty() + || !desc.isEmpty(); // if it's Attica, or it has non-empty at least author or description if ( canRate ) { textRect = QRect( leftTitleEdge, opt.rect.top() + PADDING, rightTitleEdge - leftTitleEdge, painter->fontMetrics().height() ); @@ -294,7 +299,6 @@ AccountDelegate::paint ( QPainter* painter, const QStyleOptionViewItem& option, painter->drawText( textRect, Qt::AlignVCenter | Qt::AlignLeft, title ); // author - QString author = index.data( AccountModel::AuthorRole ).toString(); int runningBottom = textRect.bottom(); if ( !author.isEmpty() && canRate ) { @@ -310,7 +314,6 @@ AccountDelegate::paint ( QPainter* painter, const QStyleOptionViewItem& option, } // description - QString desc = index.data( AccountModel::DescriptionRole ).toString(); const int descWidth = rightEdge - leftTitleEdge - PADDING; painter->setFont( descFont ); const QRect descRect( leftTitleEdge, runningBottom + PADDING, descWidth, painter->fontMetrics().height() ); diff --git a/src/libtomahawk/accounts/AccountModel.cpp b/src/libtomahawk/accounts/AccountModel.cpp index c32582eb00..637ff55a15 100644 --- a/src/libtomahawk/accounts/AccountModel.cpp +++ b/src/libtomahawk/accounts/AccountModel.cpp @@ -337,7 +337,11 @@ AccountModel::data( const QModelIndex& index, int role ) const case Qt::DecorationRole: return acct->icon(); case DescriptionRole: - return node->factory ? node->factory->description() : QString(); + return node->factory ? + ( !node->factory->description().isEmpty() ? node->factory->description() : acct->description() ) + : acct->description(); + case AuthorRole: + return acct->author(); case Qt::CheckStateRole: return acct->enabled() ? Qt::Checked : Qt::Unchecked; case AccountData: diff --git a/src/libtomahawk/accounts/ResolverAccount.cpp b/src/libtomahawk/accounts/ResolverAccount.cpp index 1384cdb635..e41630109a 100644 --- a/src/libtomahawk/accounts/ResolverAccount.cpp +++ b/src/libtomahawk/accounts/ResolverAccount.cpp @@ -66,8 +66,84 @@ ResolverAccountFactory::createFromPath( const QString& path, const QString& fact QFileInfo info( path ); return new AtticaResolverAccount( generateId( factory ), path, info.baseName() ); } - else - return new ResolverAccount( generateId( factory ), path ); + else //on filesystem, but it could be a bundle or a legacy resolver file + { + QString realPath( path ); + const QFileInfo pathInfo( path ); + + QVariantHash configuration; + + if ( pathInfo.suffix() == "axe" ) + { + QDir dir( TomahawkUtils::extractScriptPayload( pathInfo.filePath(), + pathInfo.baseName(), + "manualresolvers" ) ); + if ( !( dir.exists() && dir.isReadable() ) ) //decompression fubar + return 0; + + if ( !dir.cd( "content" ) ) //more fubar + return 0; + + QString desktopFilePath = dir.absoluteFilePath( "metadata.desktop" ); + + configuration = metadataFromDesktopFile( desktopFilePath ); + realPath = configuration[ "path" ].toString(); + if ( realPath.isEmpty() ) + return 0; + } + else //either legacy resolver or uncompressed bundle, so we look for a metadata file + { + QDir dir = pathInfo.absoluteDir();//assume we are in the code directory of a bundle + if ( dir.cdUp() && dir.cdUp() ) //go up twice to the content dir, if any + { + QString desktopFilePath = dir.absoluteFilePath( "metadata.desktop" ); + configuration = metadataFromDesktopFile( desktopFilePath ); + configuration[ "path" ] = realPath; //our initial path still overrides whatever the desktop file says + } + //else we just have empty metadata (legacy resolver without desktop file) + } + + //TODO: handle multi-account resolvers + + return new ResolverAccount( generateId( factory ), realPath, configuration ); + } +} + + +QVariantHash +ResolverAccountFactory::metadataFromDesktopFile( const QString& path ) +{ + QVariantHash result; + QFile desktopFile( path ); + if ( desktopFile.open( QIODevice::ReadOnly | QIODevice::Text ) ) + { + QTextStream desktopFileStream( &desktopFile ); + + while ( !desktopFileStream.atEnd() ) + { + QString line = desktopFileStream.readLine().trimmed(); + + if ( line.contains( QRegExp( "^X-Synchrotron-MainScript\\s*=\\s*" ) ) ) + { + line.remove( QRegExp( "^X-Synchrotron-MainScript\\s*=\\s*" ) ); + QFileInfo fi( path ); + result[ "path" ] = fi.absoluteDir().absoluteFilePath( line ); //this is our path to the JS + } + else if ( line.contains( QRegExp( "^X-KDE-PluginInfo-Author\\s*=\\s*" ) ) ) + { + line.remove( QRegExp( "^X-KDE-PluginInfo-Author\\s*=\\s*" ) ); + result[ "author" ] = line; + } + else if ( line.contains( QRegExp( "^Comment\\s*=\\s*" ) ) ) + { + line.remove( QRegExp( "^Comment\\s*=\\s*" ) ); + result[ "description" ] = line; + } + + //TODO: correct baseName and rename directory maybe? + } + } + return result; } @@ -84,10 +160,10 @@ ResolverAccount::ResolverAccount( const QString& accountId ) } -ResolverAccount::ResolverAccount( const QString& accountId, const QString& path ) +ResolverAccount::ResolverAccount( const QString& accountId, const QString& path, const QVariantHash& initialConfiguration ) : Account( accountId ) { - QVariantHash configuration; + QVariantHash configuration( initialConfiguration ); configuration[ "path" ] = path; setConfiguration( configuration ); @@ -242,6 +318,21 @@ ResolverAccount::icon() const return m_resolver.data()->icon(); } + +QString +ResolverAccount::description() const +{ + return configuration().value( "description" ).toString(); +} + + +QString +ResolverAccount::author() const +{ + return configuration().value( "author" ).toString(); +} + + /// AtticaResolverAccount AtticaResolverAccount::AtticaResolverAccount( const QString& accountId ) diff --git a/src/libtomahawk/accounts/ResolverAccount.h b/src/libtomahawk/accounts/ResolverAccount.h index 830f3c0baf..06466fade5 100644 --- a/src/libtomahawk/accounts/ResolverAccount.h +++ b/src/libtomahawk/accounts/ResolverAccount.h @@ -51,6 +51,9 @@ class DLLEXPORT ResolverAccountFactory : public AccountFactory // Internal use static Account* createFromPath( const QString& path, const QString& factoryId, bool isAttica ); + +private: + static QVariantHash metadataFromDesktopFile( const QString& path ); }; /** @@ -80,6 +83,8 @@ class DLLEXPORT ResolverAccount : public Account QString path() const; virtual QPixmap icon() const; + virtual QString description() const; + virtual QString author() const; // Not relevant virtual SipPlugin* sipPlugin() { return 0; } @@ -91,8 +96,7 @@ private slots: protected: // Created by factory, when user installs a new resolver - ResolverAccount( const QString& accountId, const QString& path ); - + ResolverAccount( const QString& accountId, const QString& path, const QVariantHash& initialConfiguration = QVariantHash() ); void hookupResolver(); QPointer m_resolver; From fd07667d76cdee0b70bd9d4695a71ab9edbd94d2 Mon Sep 17 00:00:00 2001 From: Teo Mrnjavac Date: Mon, 11 Mar 2013 22:56:47 +0100 Subject: [PATCH 39/76] Headers. --- src/libtomahawk/accounts/ResolverAccount.cpp | 1 + src/libtomahawk/accounts/ResolverAccount.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/libtomahawk/accounts/ResolverAccount.cpp b/src/libtomahawk/accounts/ResolverAccount.cpp index e41630109a..32ee531422 100644 --- a/src/libtomahawk/accounts/ResolverAccount.cpp +++ b/src/libtomahawk/accounts/ResolverAccount.cpp @@ -1,6 +1,7 @@ /* === This file is part of Tomahawk Player - === * * Copyright 2010-2011, Leo Franchi + * Copyright 2013, Teo Mrnjavac * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/libtomahawk/accounts/ResolverAccount.h b/src/libtomahawk/accounts/ResolverAccount.h index 06466fade5..3445d8f44d 100644 --- a/src/libtomahawk/accounts/ResolverAccount.h +++ b/src/libtomahawk/accounts/ResolverAccount.h @@ -1,6 +1,7 @@ /* === This file is part of Tomahawk Player - === * * Copyright 2010-2011, Leo Franchi + * Copyright 2013, Teo Mrnjavac * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by From bf76547fa7bef3f6f0c67a2ad40f7455c606a06a Mon Sep 17 00:00:00 2001 From: Teo Mrnjavac Date: Wed, 13 Mar 2013 23:11:05 +0100 Subject: [PATCH 40/76] Load resolver metadata from JSON file rather than desktop file. --- src/libtomahawk/accounts/ResolverAccount.cpp | 49 +++++++++----------- src/libtomahawk/accounts/ResolverAccount.h | 2 +- 2 files changed, 23 insertions(+), 28 deletions(-) diff --git a/src/libtomahawk/accounts/ResolverAccount.cpp b/src/libtomahawk/accounts/ResolverAccount.cpp index 32ee531422..6f498a72fb 100644 --- a/src/libtomahawk/accounts/ResolverAccount.cpp +++ b/src/libtomahawk/accounts/ResolverAccount.cpp @@ -27,6 +27,7 @@ #include "TomahawkSettings.h" #include "Source.h" #include "utils/Logger.h" +#include "qjson/parser.h" #include #include @@ -85,9 +86,9 @@ ResolverAccountFactory::createFromPath( const QString& path, const QString& fact if ( !dir.cd( "content" ) ) //more fubar return 0; - QString desktopFilePath = dir.absoluteFilePath( "metadata.desktop" ); + QString metadataFilePath = dir.absoluteFilePath( "metadata.json" ); - configuration = metadataFromDesktopFile( desktopFilePath ); + configuration = metadataFromJsonFile( metadataFilePath ); realPath = configuration[ "path" ].toString(); if ( realPath.isEmpty() ) return 0; @@ -97,8 +98,8 @@ ResolverAccountFactory::createFromPath( const QString& path, const QString& fact QDir dir = pathInfo.absoluteDir();//assume we are in the code directory of a bundle if ( dir.cdUp() && dir.cdUp() ) //go up twice to the content dir, if any { - QString desktopFilePath = dir.absoluteFilePath( "metadata.desktop" ); - configuration = metadataFromDesktopFile( desktopFilePath ); + QString metadataFilePath = dir.absoluteFilePath( "metadata.json" ); + configuration = metadataFromJsonFile( metadataFilePath ); configuration[ "path" ] = realPath; //our initial path still overrides whatever the desktop file says } //else we just have empty metadata (legacy resolver without desktop file) @@ -112,37 +113,31 @@ ResolverAccountFactory::createFromPath( const QString& path, const QString& fact QVariantHash -ResolverAccountFactory::metadataFromDesktopFile( const QString& path ) +ResolverAccountFactory::metadataFromJsonFile( const QString& path ) { QVariantHash result; - QFile desktopFile( path ); - if ( desktopFile.open( QIODevice::ReadOnly | QIODevice::Text ) ) + QFile metadataFile( path ); + if ( metadataFile.open( QIODevice::ReadOnly | QIODevice::Text ) ) { - QTextStream desktopFileStream( &desktopFile ); + QJson::Parser parser; + bool ok; + QVariantMap variant = parser.parse( metadataFile.readAll(), &ok ).toMap(); - while ( !desktopFileStream.atEnd() ) + if ( ok ) { - QString line = desktopFileStream.readLine().trimmed(); - - if ( line.contains( QRegExp( "^X-Synchrotron-MainScript\\s*=\\s*" ) ) ) - { - line.remove( QRegExp( "^X-Synchrotron-MainScript\\s*=\\s*" ) ); - QFileInfo fi( path ); - result[ "path" ] = fi.absoluteDir().absoluteFilePath( line ); //this is our path to the JS - } - else if ( line.contains( QRegExp( "^X-KDE-PluginInfo-Author\\s*=\\s*" ) ) ) + result[ "author" ] = variant[ "author" ]; + result[ "description" ] = variant[ "description" ]; + if ( !variant[ "manifest" ].isNull() ) { - line.remove( QRegExp( "^X-KDE-PluginInfo-Author\\s*=\\s*" ) ); - result[ "author" ] = line; + QVariantMap manifest = variant[ "manifest" ].toMap(); + if ( !manifest[ "main" ].isNull() ) + { + QFileInfo fi( path ); + result[ "path" ] = fi.absoluteDir().absoluteFilePath( manifest[ "main" ].toString() ); //this is our path to the JS + } } - else if ( line.contains( QRegExp( "^Comment\\s*=\\s*" ) ) ) - { - line.remove( QRegExp( "^Comment\\s*=\\s*" ) ); - result[ "description" ] = line; - } - - //TODO: correct baseName and rename directory maybe? } + //TODO: correct baseName and rename directory maybe? } return result; } diff --git a/src/libtomahawk/accounts/ResolverAccount.h b/src/libtomahawk/accounts/ResolverAccount.h index 3445d8f44d..9f25f2ade1 100644 --- a/src/libtomahawk/accounts/ResolverAccount.h +++ b/src/libtomahawk/accounts/ResolverAccount.h @@ -54,7 +54,7 @@ class DLLEXPORT ResolverAccountFactory : public AccountFactory static Account* createFromPath( const QString& path, const QString& factoryId, bool isAttica ); private: - static QVariantHash metadataFromDesktopFile( const QString& path ); + static QVariantHash metadataFromJsonFile( const QString& path ); }; /** From 259e28523bf72eef86c1d493cb7719a726dc205c Mon Sep 17 00:00:00 2001 From: Teo Mrnjavac Date: Thu, 14 Mar 2013 16:08:24 +0100 Subject: [PATCH 41/76] Return IODevices for track URLs through callbacks. --- src/libtomahawk/audio/AudioEngine.cpp | 56 +++++++++++------ src/libtomahawk/audio/AudioEngine.h | 4 +- src/libtomahawk/network/Servent.cpp | 63 +++++++++++++------ src/libtomahawk/network/Servent.h | 16 +++-- src/libtomahawk/network/StreamConnection.cpp | 20 ++++-- src/libtomahawk/network/StreamConnection.h | 4 +- .../resolvers/QtScriptResolver.cpp | 21 +++++-- src/libtomahawk/resolvers/QtScriptResolver.h | 4 +- src/web/Api_v1.cpp | 15 ++++- src/web/Api_v1.h | 8 +++ 10 files changed, 150 insertions(+), 61 deletions(-) diff --git a/src/libtomahawk/audio/AudioEngine.cpp b/src/libtomahawk/audio/AudioEngine.cpp index fe776a707a..5be27baa2e 100644 --- a/src/libtomahawk/audio/AudioEngine.cpp +++ b/src/libtomahawk/audio/AudioEngine.cpp @@ -2,6 +2,7 @@ * * Copyright 2010-2012, Christian Muehlhaeuser * Copyright 2010-2012, Jeff Mitchell + * Copyright 2013, Teo Mrnjavac * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -39,6 +40,8 @@ #include "utils/Logger.h" #include "playlist/SingleTrackPlaylistInterface.h" +#include + #include #include #include @@ -430,30 +433,43 @@ AudioEngine::onNowPlayingInfoReady( const Tomahawk::InfoSystem::InfoType type ) } -bool +void AudioEngine::loadTrack( const Tomahawk::result_ptr& result ) { - bool err = false; + if ( result.isNull() ) { - QSharedPointer io; + stop(); + return; + } - if ( result.isNull() ) - err = true; - else - { - setCurrentTrack( result ); + setCurrentTrack( result ); - if ( !TomahawkUtils::isHttpResult( m_currentTrack->url() ) && - !TomahawkUtils::isLocalResult( m_currentTrack->url() ) ) - { - io = Servent::instance()->getIODeviceForUrl( m_currentTrack ); + if ( !TomahawkUtils::isHttpResult( m_currentTrack->url() ) && + !TomahawkUtils::isLocalResult( m_currentTrack->url() ) ) + { + boost::function< void ( QSharedPointer< QIODevice >& ) > callback = + boost::bind( &AudioEngine::performLoadTrack, this, result, _1 ); + Servent::instance()->getIODeviceForUrl( m_currentTrack, callback ); + } + else + { + QSharedPointer< QIODevice > io; + performLoadTrack( result, io ); + } +} - if ( !io || io.isNull() ) - { - tLog() << "Error getting iodevice for" << result->url(); - err = true; - } - } + +void +AudioEngine::performLoadTrack( const Tomahawk::result_ptr& result, QSharedPointer< QIODevice >& io ) +{ + bool err = false; + { + if ( !TomahawkUtils::isHttpResult( m_currentTrack->url() ) && + !TomahawkUtils::isLocalResult( m_currentTrack->url() ) && + ( !io || io.isNull() ) ) + { + tLog() << "Error getting iodevice for" << result->url(); + err = true; } if ( !err ) @@ -520,11 +536,11 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result ) if ( err ) { stop(); - return false; + return; } m_waitingOnNewTrack = false; - return true; + return; } diff --git a/src/libtomahawk/audio/AudioEngine.h b/src/libtomahawk/audio/AudioEngine.h index 67d83aaef2..99d22c0a6d 100644 --- a/src/libtomahawk/audio/AudioEngine.h +++ b/src/libtomahawk/audio/AudioEngine.h @@ -2,6 +2,7 @@ * * Copyright 2010-2012, Christian Muehlhaeuser * Copyright 2010-2012, Jeff Mitchell + * Copyright 2013, Teo Mrnjavac * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -128,7 +129,8 @@ public slots: void error( AudioEngine::AudioErrorCode errorCode ); private slots: - bool loadTrack( const Tomahawk::result_ptr& result ); + void loadTrack( const Tomahawk::result_ptr& result ); //async! + void performLoadTrack( const Tomahawk::result_ptr& result, QSharedPointer< QIODevice >& io ); //only call from loadTrack kthxbi void loadPreviousTrack(); void loadNextTrack(); diff --git a/src/libtomahawk/network/Servent.cpp b/src/libtomahawk/network/Servent.cpp index 761a75e734..957701ae35 100644 --- a/src/libtomahawk/network/Servent.cpp +++ b/src/libtomahawk/network/Servent.cpp @@ -2,6 +2,7 @@ * * Copyright 2010-2011, Christian Muehlhaeuser * Copyright 2010-2012, Jeff Mitchell + * Copyright 2013, Teo Mrnjavac * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -75,17 +76,18 @@ Servent::Servent( QObject* parent ) setProxy( QNetworkProxy::NoProxy ); { - boost::function(result_ptr)> fac = boost::bind( &Servent::localFileIODeviceFactory, this, _1 ); + // _1 = result, _2 = callback function for IODevice + IODeviceFactoryFunc fac = boost::bind( &Servent::localFileIODeviceFactory, this, _1, _2 ); this->registerIODeviceFactory( "file", fac ); } { - boost::function(result_ptr)> fac = boost::bind( &Servent::remoteIODeviceFactory, this, _1 ); + IODeviceFactoryFunc fac = boost::bind( &Servent::remoteIODeviceFactory, this, _1, _2 ); this->registerIODeviceFactory( "servent", fac ); } { - boost::function(result_ptr)> fac = boost::bind( &Servent::httpIODeviceFactory, this, _1 ); + IODeviceFactoryFunc fac = boost::bind( &Servent::httpIODeviceFactory, this, _1, _2 ); this->registerIODeviceFactory( "http", fac ); this->registerIODeviceFactory( "https", fac ); } @@ -944,8 +946,9 @@ Servent::claimOffer( ControlConnection* cc, const QString &nodeid, const QString } -QSharedPointer -Servent::remoteIODeviceFactory( const result_ptr& result ) +void +Servent::remoteIODeviceFactory( const Tomahawk::result_ptr& result, + boost::function< void ( QSharedPointer< QIODevice >& ) > callback ) { QSharedPointer sp; @@ -954,12 +957,18 @@ Servent::remoteIODeviceFactory( const result_ptr& result ) const QString fileId = parts.at( 1 ); source_ptr s = SourceList::instance()->get( sourceName ); if ( s.isNull() || !s->controlConnection() ) - return sp; + { + callback( sp ); + return; + } ControlConnection* cc = s->controlConnection(); StreamConnection* sc = new StreamConnection( this, cc, fileId, result ); createParallelConnection( cc, sc, QString( "FILE_REQUEST_KEY:%1" ).arg( fileId ) ); - return sc->iodevice(); + + //boost::functions cannot accept temporaries as parameters + sp = sc->iodevice(); + callback( sp ); } @@ -1066,45 +1075,61 @@ Servent::triggerDBSync() void -Servent::registerIODeviceFactory( const QString &proto, boost::function(Tomahawk::result_ptr)> fac ) +Servent::registerIODeviceFactory( const QString &proto, + IODeviceFactoryFunc fac ) { m_iofactories.insert( proto, fac ); } -QSharedPointer -Servent::getIODeviceForUrl( const Tomahawk::result_ptr& result ) +void +Servent::getIODeviceForUrl( const Tomahawk::result_ptr& result, + boost::function< void ( QSharedPointer< QIODevice >& ) > callback ) { QSharedPointer sp; QRegExp rx( "^([a-zA-Z0-9]+)://(.+)$" ); if ( rx.indexIn( result->url() ) == -1 ) - return sp; + { + callback( sp ); + return; + } const QString proto = rx.cap( 1 ); if ( !m_iofactories.contains( proto ) ) - return sp; + { + callback( sp ); + return; + } - return m_iofactories.value( proto )( result ); + //QtScriptResolverHelper::customIODeviceFactory is async! + m_iofactories.value( proto )( result, callback ); } -QSharedPointer -Servent::localFileIODeviceFactory( const Tomahawk::result_ptr& result ) +void +Servent::localFileIODeviceFactory( const Tomahawk::result_ptr& result, + boost::function< void ( QSharedPointer< QIODevice >& ) > callback ) { // ignore "file://" at front of url QFile* io = new QFile( result->url().mid( QString( "file://" ).length() ) ); if ( io ) io->open( QIODevice::ReadOnly ); - return QSharedPointer( io ); + //boost::functions cannot accept temporaries as parameters + QSharedPointer< QIODevice > sp = QSharedPointer( io ); + callback( sp ); } -QSharedPointer -Servent::httpIODeviceFactory( const Tomahawk::result_ptr& result ) +void +Servent::httpIODeviceFactory( const Tomahawk::result_ptr& result, + boost::function< void ( QSharedPointer< QIODevice >& ) > callback ) { QNetworkRequest req( result->url() ); QNetworkReply* reply = TomahawkUtils::nam()->get( req ); - return QSharedPointer( reply, &QObject::deleteLater ); + + //boost::functions cannot accept temporaries as parameters + QSharedPointer< QIODevice > sp = QSharedPointer< QIODevice >( reply, &QObject::deleteLater ); + callback( sp ); } diff --git a/src/libtomahawk/network/Servent.h b/src/libtomahawk/network/Servent.h index d4052a97b8..7452fdb57d 100644 --- a/src/libtomahawk/network/Servent.h +++ b/src/libtomahawk/network/Servent.h @@ -2,6 +2,7 @@ * * Copyright 2010-2011, Christian Muehlhaeuser * Copyright 2010-2012, Jeff Mitchell + * Copyright 2013, Teo Mrnjavac * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -54,6 +55,9 @@ class PortFwdThread; class PeerInfo; class SipInfo; +typedef boost::function< void( const Tomahawk::result_ptr&, + boost::function< void( QSharedPointer< QIODevice >& ) > )> IODeviceFactoryFunc; + // this is used to hold a bit of state, so when a connected signal is emitted // from a socket, we can associate it with a Connection object etc. class DLLEXPORT QTcpSocketExtra : public QTcpSocket @@ -121,7 +125,6 @@ public slots: QString externalAddress() const { return !m_externalHostname.isNull() ? m_externalHostname : m_externalAddress.toString(); } int externalPort() const { return m_externalPort; } - QSharedPointer< QIODevice > remoteIODeviceFactory( const Tomahawk::result_ptr& ); static bool isIPWhitelisted( QHostAddress ip ); bool connectedToSession( const QString& session ); @@ -129,10 +132,11 @@ public slots: QList< StreamConnection* > streams() const { return m_scsessions; } - QSharedPointer< QIODevice > getIODeviceForUrl( const Tomahawk::result_ptr& result ); - void registerIODeviceFactory( const QString &proto, boost::function< QSharedPointer< QIODevice >(Tomahawk::result_ptr) > fac ); - QSharedPointer< QIODevice > localFileIODeviceFactory( const Tomahawk::result_ptr& result ); - QSharedPointer< QIODevice > httpIODeviceFactory( const Tomahawk::result_ptr& result ); + void getIODeviceForUrl( const Tomahawk::result_ptr& result, boost::function< void ( QSharedPointer< QIODevice >& ) > callback ); + void registerIODeviceFactory( const QString &proto, IODeviceFactoryFunc fac ); + void remoteIODeviceFactory( const Tomahawk::result_ptr& result, boost::function< void ( QSharedPointer< QIODevice >& ) > callback ); + void localFileIODeviceFactory( const Tomahawk::result_ptr& result, boost::function< void ( QSharedPointer< QIODevice >& ) > callback ); + void httpIODeviceFactory( const Tomahawk::result_ptr& result, boost::function< void ( QSharedPointer< QIODevice >& ) > callback ); bool isReady() const { return m_ready; }; @@ -184,7 +188,7 @@ private slots: QList< StreamConnection* > m_scsessions; QMutex m_ftsession_mut; - QMap< QString,boost::function< QSharedPointer< QIODevice >(Tomahawk::result_ptr) > > m_iofactories; + QMap< QString, IODeviceFactoryFunc > m_iofactories; QPointer< PortFwdThread > m_portfwd; static Servent* s_instance; diff --git a/src/libtomahawk/network/StreamConnection.cpp b/src/libtomahawk/network/StreamConnection.cpp index 9f8b4c47bf..fe6d243625 100644 --- a/src/libtomahawk/network/StreamConnection.cpp +++ b/src/libtomahawk/network/StreamConnection.cpp @@ -2,6 +2,7 @@ * * Copyright 2010-2011, Christian Muehlhaeuser * Copyright 2010-2011, Jeff Mitchell + * Copyright 2013, Teo Mrnjavac * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,10 +20,7 @@ #include "StreamConnection.h" -#include - #include "Result.h" - #include "BufferIoDevice.h" #include "network/ControlConnection.h" #include "network/Servent.h" @@ -31,6 +29,10 @@ #include "SourceList.h" #include "utils/Logger.h" +#include + +#include + using namespace Tomahawk; @@ -179,8 +181,16 @@ StreamConnection::startSending( const Tomahawk::result_ptr& result ) m_result = result; qDebug() << "Starting to transmit" << m_result->url(); - QSharedPointer io = Servent::instance()->getIODeviceForUrl( m_result ); - if( !io ) + boost::function< void ( QSharedPointer< QIODevice >& ) > callback = + boost::bind( &StreamConnection::reallyStartSending, this, result, _1 ); + Servent::instance()->getIODeviceForUrl( m_result, callback ); +} + + +void +StreamConnection::reallyStartSending( const Tomahawk::result_ptr& result, QSharedPointer< QIODevice >& io ) +{ + if( !io || io.isNull() ) { qDebug() << "Couldn't read from source:" << m_result->url(); shutdown(); diff --git a/src/libtomahawk/network/StreamConnection.h b/src/libtomahawk/network/StreamConnection.h index 52e2943dea..f41351ba4c 100644 --- a/src/libtomahawk/network/StreamConnection.h +++ b/src/libtomahawk/network/StreamConnection.h @@ -2,6 +2,7 @@ * * Copyright 2010-2011, Christian Muehlhaeuser * Copyright 2010-2011, Jeff Mitchell + * Copyright 2013, Teo Mrnjavac * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -71,7 +72,8 @@ protected slots: virtual void handleMsg( msg_ptr msg ); private slots: - void startSending( const Tomahawk::result_ptr& ); + void startSending( const Tomahawk::result_ptr& result ); + void reallyStartSending( const Tomahawk::result_ptr& result, QSharedPointer< QIODevice >& io ); //only called back from startSending void sendSome(); void showStats( qint64 tx, qint64 rx ); diff --git a/src/libtomahawk/resolvers/QtScriptResolver.cpp b/src/libtomahawk/resolvers/QtScriptResolver.cpp index ddda02f604..c13afe4b4a 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.cpp +++ b/src/libtomahawk/resolvers/QtScriptResolver.cpp @@ -332,7 +332,9 @@ QtScriptResolverHelper::md5( const QByteArray& input ) void QtScriptResolverHelper::addCustomUrlHandler( const QString& protocol, const QString& callbackFuncName ) { - boost::function(Tomahawk::result_ptr)> fac = boost::bind( &QtScriptResolverHelper::customIODeviceFactory, this, _1 ); + boost::function< void( const Tomahawk::result_ptr&, + boost::function< void( QSharedPointer< QIODevice >& ) > )> fac = + boost::bind( &QtScriptResolverHelper::customIODeviceFactory, this, _1, _2 ); Servent::instance()->registerIODeviceFactory( protocol, fac ); m_urlCallback = callbackFuncName; @@ -502,8 +504,9 @@ QtScriptResolverHelper::showWebInspector() } -QSharedPointer< QIODevice > -QtScriptResolverHelper::customIODeviceFactory( const Tomahawk::result_ptr& result ) +void +QtScriptResolverHelper::customIODeviceFactory( const Tomahawk::result_ptr& result, + boost::function< void( QSharedPointer< QIODevice >& ) > callback ) { QString urlStr; QVariantMap request; @@ -530,14 +533,22 @@ QtScriptResolverHelper::customIODeviceFactory( const Tomahawk::result_ptr& resul urlStr = jsResult.toString(); } + QSharedPointer< QIODevice > sp; if ( urlStr.isEmpty() ) - return QSharedPointer< QIODevice >(); + { + + callback( sp ); + return; + } QUrl url = QUrl::fromEncoded( urlStr.toUtf8() ); req.setUrl( url ); tDebug() << "Creating a QNetowrkReply with url:" << req.url().toString(); QNetworkReply* reply = TomahawkUtils::nam()->get( req ); - return QSharedPointer( reply, &QObject::deleteLater ); + + //boost::functions cannot accept temporaries as parameters + sp = QSharedPointer< QIODevice >( reply, &QObject::deleteLater ); + callback( sp ); } diff --git a/src/libtomahawk/resolvers/QtScriptResolver.h b/src/libtomahawk/resolvers/QtScriptResolver.h index 2ad3530365..250414272b 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.h +++ b/src/libtomahawk/resolvers/QtScriptResolver.h @@ -64,7 +64,6 @@ Q_OBJECT Q_INVOKABLE QByteArray base64Encode( const QByteArray& input ); Q_INVOKABLE QByteArray base64Decode( const QByteArray& input ); - // send ID3Tags of the stream as argument of the callback function Q_INVOKABLE void readCloudFile( const QString& fileName, const QString& fileId, const QString& sizeS, const QString& mime_type, const QVariant& requestJS, const QString& javascriptCallbackFunction, @@ -76,7 +75,8 @@ Q_OBJECT Q_INVOKABLE void showWebInspector(); - QSharedPointer customIODeviceFactory( const Tomahawk::result_ptr& result ); + void customIODeviceFactory( const Tomahawk::result_ptr& result, + boost::function< void( QSharedPointer< QIODevice >& ) > callback ); // async public slots: QByteArray readRaw( const QString& fileName ); diff --git a/src/web/Api_v1.cpp b/src/web/Api_v1.cpp index 9ac84660cf..b245553396 100644 --- a/src/web/Api_v1.cpp +++ b/src/web/Api_v1.cpp @@ -3,6 +3,7 @@ * Copyright 2010-2011, Christian Muehlhaeuser * Copyright 2010-2011, Jeff Mitchell * Copyright 2010-2011, Leo Franchi + * Copyright 2013, Teo Mrnjavac * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,6 +31,8 @@ #include "Pipeline.h" #include "Source.h" +#include + #include @@ -189,8 +192,16 @@ Api_v1::sid( QxtWebRequestEvent* event, QString unused ) return send404( event ); } - QSharedPointer iodev = Servent::instance()->getIODeviceForUrl( rp ); - if ( iodev.isNull() ) + boost::function< void ( QSharedPointer< QIODevice >& ) > callback = + boost::bind( &Api_v1::processSid, this, event, rp, _1 ); + Servent::instance()->getIODeviceForUrl( rp, callback ); +} + + +void +Api_v1::processSid( QxtWebRequestEvent* event, Tomahawk::result_ptr& rp, QSharedPointer< QIODevice >& iodev ) +{ + if ( !iodev || iodev.isNull() ) { return send404( event ); // 503? } diff --git a/src/web/Api_v1.h b/src/web/Api_v1.h index 4ad4c88cf6..06cb411dc1 100644 --- a/src/web/Api_v1.h +++ b/src/web/Api_v1.h @@ -2,6 +2,7 @@ * * Copyright 2010-2011, Christian Muehlhaeuser * Copyright 2010-2011, Leo Franchi + * Copyright 2013, Teo Mrnjavac * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -36,6 +37,12 @@ #include #include +namespace Tomahawk +{ + class Result; + typedef QSharedPointer< Result > result_ptr; +} + class Api_v1 : public QxtWebSlotService { Q_OBJECT @@ -70,6 +77,7 @@ public slots: void index( QxtWebRequestEvent* event ); private: + void processSid( QxtWebRequestEvent* event, Tomahawk::result_ptr&, QSharedPointer< QIODevice >& ); QxtWebRequestEvent* m_storedEvent; }; From 091b1fadf77e72b28c27281e4218d38cf245819e Mon Sep 17 00:00:00 2001 From: Teo Mrnjavac Date: Thu, 14 Mar 2013 18:56:24 +0100 Subject: [PATCH 42/76] Allow async streamUrl reports for custom IODeviceFactory resolvers. --- .../resolvers/QtScriptResolver.cpp | 55 +++++++++++++++++-- src/libtomahawk/resolvers/QtScriptResolver.h | 6 +- 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/src/libtomahawk/resolvers/QtScriptResolver.cpp b/src/libtomahawk/resolvers/QtScriptResolver.cpp index c13afe4b4a..af6901d0bc 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.cpp +++ b/src/libtomahawk/resolvers/QtScriptResolver.cpp @@ -95,6 +95,7 @@ QtScriptResolverHelper::QtScriptResolverHelper( const QString& scriptPath, QtScriptResolver* parent ) : QObject( parent ) + , m_urlCallbackIsAsync( false ) { m_scriptPath = scriptPath; m_resolver = parent; @@ -330,8 +331,12 @@ QtScriptResolverHelper::md5( const QByteArray& input ) void -QtScriptResolverHelper::addCustomUrlHandler( const QString& protocol, const QString& callbackFuncName ) +QtScriptResolverHelper::addCustomUrlHandler( const QString& protocol, + const QString& callbackFuncName, + const QString& async ) { + m_urlCallbackIsAsync = ( async.toLower() == "true" ) ? true : false; + boost::function< void( const Tomahawk::result_ptr&, boost::function< void( QSharedPointer< QIODevice >& ) > )> fac = boost::bind( &QtScriptResolverHelper::customIODeviceFactory, this, _1, _2 ); @@ -533,16 +538,56 @@ QtScriptResolverHelper::customIODeviceFactory( const Tomahawk::result_ptr& resul urlStr = jsResult.toString(); } - QSharedPointer< QIODevice > sp; - if ( urlStr.isEmpty() ) + //can be sync or async + QString origResultUrl = QString( QUrl( result->url() ).toEncoded() ); + + if ( m_urlCallbackIsAsync ) + { + QString qid = uuid(); + QString getUrl = QString( "Tomahawk.resolver.instance.%1( '%2', '%3' );" ).arg( m_urlCallback ) + .arg( qid ) + .arg( origResultUrl ); + + m_streamCallbacks.insert( qid, callback ); + m_resolver->m_engine->mainFrame()->evaluateJavaScript( getUrl ); + } + else { + QString getUrl = QString( "Tomahawk.resolver.instance.%1( '%2' );" ).arg( m_urlCallback ) + .arg( origResultUrl ); + + QString urlStr = m_resolver->m_engine->mainFrame()->evaluateJavaScript( getUrl ).toString(); + + returnStreamUrl( urlStr, callback ); + } +} + +void +QtScriptResolverHelper::reportStreamUrl( const QString& qid, + const QString& streamUrl ) +{ + if ( !m_streamCallbacks.contains( qid ) ) + return; + + boost::function< void( QSharedPointer< QIODevice >& ) > callback = m_streamCallbacks.take( qid ); + + returnStreamUrl( streamUrl, callback ); +} + + +void +QtScriptResolverHelper::returnStreamUrl( const QString& streamUrl, boost::function< void( QSharedPointer< QIODevice >& ) > callback ) +{ + QSharedPointer< QIODevice > sp; + if ( streamUrl.isEmpty() ) + { callback( sp ); return; } - QUrl url = QUrl::fromEncoded( urlStr.toUtf8() ); - req.setUrl( url ); + QUrl url = QUrl::fromEncoded( streamUrl.toUtf8() ); + QNetworkRequest req( url ); tDebug() << "Creating a QNetowrkReply with url:" << req.url().toString(); QNetworkReply* reply = TomahawkUtils::nam()->get( req ); diff --git a/src/libtomahawk/resolvers/QtScriptResolver.h b/src/libtomahawk/resolvers/QtScriptResolver.h index 250414272b..b44df19113 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.h +++ b/src/libtomahawk/resolvers/QtScriptResolver.h @@ -59,7 +59,8 @@ Q_OBJECT Q_INVOKABLE QString hmac( const QByteArray& key, const QByteArray& input ); Q_INVOKABLE QString md5( const QByteArray& input ); - Q_INVOKABLE void addCustomUrlHandler( const QString& protocol, const QString& callbackFuncName ); + Q_INVOKABLE void addCustomUrlHandler( const QString& protocol, const QString& callbackFuncName, const QString& async = "false" ); + Q_INVOKABLE void reportStreamUrl( const QString& origResultUrl, const QString& streamUrl ); Q_INVOKABLE QByteArray base64Encode( const QByteArray& input ); Q_INVOKABLE QByteArray base64Decode( const QByteArray& input ); @@ -98,7 +99,10 @@ public slots: void reportCapabilities( const QVariant& capabilities ); private: + void returnStreamUrl( const QString& streamUrl, boost::function< void( QSharedPointer< QIODevice >& ) > callback ); QString m_scriptPath, m_urlCallback; + QHash< QString, boost::function< void( QSharedPointer< QIODevice >& ) > > m_streamCallbacks; + bool m_urlCallbackIsAsync; QVariantMap m_resolverConfig; QtScriptResolver* m_resolver; #ifdef QCA2_FOUND From 4611dcaf82ea7d296cf8ad8329442fd1b20cf8f5 Mon Sep 17 00:00:00 2001 From: Teo Mrnjavac Date: Thu, 14 Mar 2013 19:02:50 +0100 Subject: [PATCH 43/76] Use a more explicit parameter name. --- src/libtomahawk/resolvers/QtScriptResolver.cpp | 4 ++-- src/libtomahawk/resolvers/QtScriptResolver.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libtomahawk/resolvers/QtScriptResolver.cpp b/src/libtomahawk/resolvers/QtScriptResolver.cpp index af6901d0bc..a938d3abad 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.cpp +++ b/src/libtomahawk/resolvers/QtScriptResolver.cpp @@ -333,9 +333,9 @@ QtScriptResolverHelper::md5( const QByteArray& input ) void QtScriptResolverHelper::addCustomUrlHandler( const QString& protocol, const QString& callbackFuncName, - const QString& async ) + const QString& isAsynchronous ) { - m_urlCallbackIsAsync = ( async.toLower() == "true" ) ? true : false; + m_urlCallbackIsAsync = ( isAsynchronous.toLower() == "true" ) ? true : false; boost::function< void( const Tomahawk::result_ptr&, boost::function< void( QSharedPointer< QIODevice >& ) > )> fac = diff --git a/src/libtomahawk/resolvers/QtScriptResolver.h b/src/libtomahawk/resolvers/QtScriptResolver.h index b44df19113..8db8aa9d10 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.h +++ b/src/libtomahawk/resolvers/QtScriptResolver.h @@ -59,7 +59,7 @@ Q_OBJECT Q_INVOKABLE QString hmac( const QByteArray& key, const QByteArray& input ); Q_INVOKABLE QString md5( const QByteArray& input ); - Q_INVOKABLE void addCustomUrlHandler( const QString& protocol, const QString& callbackFuncName, const QString& async = "false" ); + Q_INVOKABLE void addCustomUrlHandler( const QString& protocol, const QString& callbackFuncName, const QString& isAsynchronous = "false" ); Q_INVOKABLE void reportStreamUrl( const QString& origResultUrl, const QString& streamUrl ); Q_INVOKABLE QByteArray base64Encode( const QByteArray& input ); From dba1ee694285eec0e6963549b11c69c311f4d8cf Mon Sep 17 00:00:00 2001 From: Teo Mrnjavac Date: Thu, 14 Mar 2013 19:11:18 +0100 Subject: [PATCH 44/76] Whoops :) --- src/libtomahawk/resolvers/QtScriptResolver.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/resolvers/QtScriptResolver.h b/src/libtomahawk/resolvers/QtScriptResolver.h index 8db8aa9d10..fcf3c399ef 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.h +++ b/src/libtomahawk/resolvers/QtScriptResolver.h @@ -60,7 +60,7 @@ Q_OBJECT Q_INVOKABLE QString md5( const QByteArray& input ); Q_INVOKABLE void addCustomUrlHandler( const QString& protocol, const QString& callbackFuncName, const QString& isAsynchronous = "false" ); - Q_INVOKABLE void reportStreamUrl( const QString& origResultUrl, const QString& streamUrl ); + Q_INVOKABLE void reportStreamUrl( const QString& qid, const QString& streamUrl ); Q_INVOKABLE QByteArray base64Encode( const QByteArray& input ); Q_INVOKABLE QByteArray base64Decode( const QByteArray& input ); From 2a3e1e99461d50cd252920034886cf2aa9582bdd Mon Sep 17 00:00:00 2001 From: Teo Mrnjavac Date: Fri, 15 Mar 2013 11:43:37 +0100 Subject: [PATCH 45/76] Correctly extract. --- src/SettingsDialog.cpp | 1 + src/libtomahawk/accounts/ResolverAccount.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/SettingsDialog.cpp b/src/SettingsDialog.cpp index 4e86932301..70bb2b11fb 100644 --- a/src/SettingsDialog.cpp +++ b/src/SettingsDialog.cpp @@ -491,6 +491,7 @@ SettingsDialog::installFromFile() Account* acct = AccountManager::instance()->accountFromPath( resolver ); + Q_ASSERT( acct ); AccountManager::instance()->addAccount( acct ); TomahawkSettings::instance()->addAccount( acct->accountId() ); AccountManager::instance()->enableAccount( acct ); diff --git a/src/libtomahawk/accounts/ResolverAccount.cpp b/src/libtomahawk/accounts/ResolverAccount.cpp index 6f498a72fb..2e1f0655f1 100644 --- a/src/libtomahawk/accounts/ResolverAccount.cpp +++ b/src/libtomahawk/accounts/ResolverAccount.cpp @@ -78,7 +78,7 @@ ResolverAccountFactory::createFromPath( const QString& path, const QString& fact if ( pathInfo.suffix() == "axe" ) { QDir dir( TomahawkUtils::extractScriptPayload( pathInfo.filePath(), - pathInfo.baseName(), + pathInfo.completeBaseName(), "manualresolvers" ) ); if ( !( dir.exists() && dir.isReadable() ) ) //decompression fubar return 0; From 7a2147fa705ffec03b21e23f40bf2aa414c99bb7 Mon Sep 17 00:00:00 2001 From: Teo Mrnjavac Date: Fri, 15 Mar 2013 14:41:06 +0100 Subject: [PATCH 46/76] Added required scripts loading support to QtScriptResolver. The good: * you can now add multiple scripts to be loaded for a single resolver before the main script, specified in metadata.json in a bundle. The bad: * it adds some complexity, and it's not tested at all. The ugly: * passing configuration from ResolverAccountFactory as QVariantHash, but that's not new, * changing ResolverFactoryFunc, * an added optional QStringList parameter to Pipeline::addScriptResolver, * the inevitable uselessness of this parameter in ScriptResolver. --- src/TomahawkApp.cpp | 4 +- src/libtomahawk/Pipeline.cpp | 4 +- src/libtomahawk/Pipeline.h | 4 +- src/libtomahawk/Typedefs.h | 2 +- src/libtomahawk/accounts/ResolverAccount.cpp | 37 ++++++++++++++++--- src/libtomahawk/accounts/ResolverAccount.h | 2 +- .../resolvers/QtScriptResolver.cpp | 22 +++++++++-- src/libtomahawk/resolvers/QtScriptResolver.h | 5 ++- src/libtomahawk/resolvers/ScriptResolver.cpp | 4 +- src/libtomahawk/resolvers/ScriptResolver.h | 2 +- 10 files changed, 65 insertions(+), 21 deletions(-) diff --git a/src/TomahawkApp.cpp b/src/TomahawkApp.cpp index cc0a7d5f54..252108f026 100644 --- a/src/TomahawkApp.cpp +++ b/src/TomahawkApp.cpp @@ -201,8 +201,8 @@ TomahawkApp::init() m_scanManager = QPointer( new ScanManager( this ) ); #ifndef ENABLE_HEADLESS - Pipeline::instance()->addExternalResolverFactory( boost::bind( &QtScriptResolver::factory, _1 ) ); - Pipeline::instance()->addExternalResolverFactory( boost::bind( &ScriptResolver::factory, _1 ) ); + Pipeline::instance()->addExternalResolverFactory( boost::bind( &QtScriptResolver::factory, _1, _2 ) ); + Pipeline::instance()->addExternalResolverFactory( boost::bind( &ScriptResolver::factory, _1, _2 ) ); new ActionCollection( this ); connect( ActionCollection::instance()->getAction( "quit" ), SIGNAL( triggered() ), SLOT( quit() ), Qt::UniqueConnection ); diff --git a/src/libtomahawk/Pipeline.cpp b/src/libtomahawk/Pipeline.cpp index e4e105d347..44b93812c7 100644 --- a/src/libtomahawk/Pipeline.cpp +++ b/src/libtomahawk/Pipeline.cpp @@ -137,13 +137,13 @@ Pipeline::addExternalResolverFactory( ResolverFactoryFunc resolverFactory ) Tomahawk::ExternalResolver* -Pipeline::addScriptResolver( const QString& path ) +Pipeline::addScriptResolver( const QString& path, const QStringList& additionalScriptPaths ) { ExternalResolver* res = 0; foreach ( ResolverFactoryFunc factory, m_resolverFactories ) { - res = factory( path ); + res = factory( path, additionalScriptPaths ); if ( !res ) continue; diff --git a/src/libtomahawk/Pipeline.h b/src/libtomahawk/Pipeline.h index a1dcb72587..e08f9412cb 100644 --- a/src/libtomahawk/Pipeline.h +++ b/src/libtomahawk/Pipeline.h @@ -36,7 +36,7 @@ namespace Tomahawk { class Resolver; class ExternalResolver; -typedef boost::function ResolverFactoryFunc; +typedef boost::function ResolverFactoryFunc; class DLLEXPORT Pipeline : public QObject { @@ -58,7 +58,7 @@ Q_OBJECT void reportArtists( QID qid, const QList< artist_ptr >& artists ); void addExternalResolverFactory( ResolverFactoryFunc resolverFactory ); - Tomahawk::ExternalResolver* addScriptResolver( const QString& scriptPath ); + Tomahawk::ExternalResolver* addScriptResolver( const QString& scriptPath, const QStringList& additionalScriptPaths = QStringList() ); void stopScriptResolver( const QString& scriptPath ); void removeScriptResolver( const QString& scriptPath ); QList< QPointer< ExternalResolver > > scriptResolvers() const { return m_scriptResolvers; } diff --git a/src/libtomahawk/Typedefs.h b/src/libtomahawk/Typedefs.h index daf5a98f2f..f54aa57c8f 100644 --- a/src/libtomahawk/Typedefs.h +++ b/src/libtomahawk/Typedefs.h @@ -89,7 +89,7 @@ namespace Tomahawk }; class ExternalResolver; - typedef boost::function ResolverFactoryFunc; + typedef boost::function ResolverFactoryFunc; namespace PlaylistModes { enum RepeatMode { NoRepeat, RepeatOne, RepeatAll }; diff --git a/src/libtomahawk/accounts/ResolverAccount.cpp b/src/libtomahawk/accounts/ResolverAccount.cpp index 2e1f0655f1..a3591caea3 100644 --- a/src/libtomahawk/accounts/ResolverAccount.cpp +++ b/src/libtomahawk/accounts/ResolverAccount.cpp @@ -63,15 +63,23 @@ Account* ResolverAccountFactory::createFromPath( const QString& path, const QString& factory, bool isAttica ) { qDebug() << "Creating ResolverAccount from path:" << path << "is attica" << isAttica; + + const QFileInfo pathInfo( path ); + if ( isAttica ) { - QFileInfo info( path ); - return new AtticaResolverAccount( generateId( factory ), path, info.baseName() ); + QVariantHash configuration; + QDir dir = pathInfo.absoluteDir();//assume we are in the code directory of a bundle + if ( dir.cdUp() && dir.cdUp() ) //go up twice to the content dir, if any + { + QString metadataFilePath = dir.absoluteFilePath( "metadata.json" ); + configuration = metadataFromJsonFile( metadataFilePath ); + } + return new AtticaResolverAccount( generateId( factory ), path, pathInfo.baseName(), configuration ); } else //on filesystem, but it could be a bundle or a legacy resolver file { QString realPath( path ); - const QFileInfo pathInfo( path ); QVariantHash configuration; @@ -135,6 +143,16 @@ ResolverAccountFactory::metadataFromJsonFile( const QString& path ) QFileInfo fi( path ); result[ "path" ] = fi.absoluteDir().absoluteFilePath( manifest[ "main" ].toString() ); //this is our path to the JS } + if ( !manifest[ "scripts" ].isNull() ) + { + QStringList scripts; + foreach ( QString s, manifest[ "scripts" ].toStringList() ) + { + QFileInfo fi( path ); + scripts << fi.absoluteDir().absoluteFilePath( s ); + } + result[ "scripts" ] = scripts; + } } } //TODO: correct baseName and rename directory maybe? @@ -161,6 +179,7 @@ ResolverAccount::ResolverAccount( const QString& accountId, const QString& path, { QVariantHash configuration( initialConfiguration ); configuration[ "path" ] = path; + setConfiguration( configuration ); init( path ); @@ -200,7 +219,13 @@ ResolverAccount::hookupResolver() { tDebug() << "Hooking up resolver:" << configuration().value( "path" ).toString() << enabled(); - m_resolver = QPointer< ExternalResolverGui >( qobject_cast< ExternalResolverGui* >( Pipeline::instance()->addScriptResolver( configuration().value( "path" ).toString() ) ) ); + QString mainScriptPath = configuration().value( "path" ).toString(); + QStringList additionalPaths; + if ( configuration().contains( "scripts" ) ) + additionalPaths = configuration().value( "scripts" ).toStringList(); + + Tomahawk::ExternalResolver* er = Pipeline::instance()->addScriptResolver( mainScriptPath, additionalPaths ); + m_resolver = QPointer< ExternalResolverGui >( qobject_cast< ExternalResolverGui* >( er ) ); connect( m_resolver.data(), SIGNAL( changed() ), this, SLOT( resolverChanged() ) ); // What resolver do we have here? Should only be types that are 'real' resolvers @@ -341,8 +366,8 @@ AtticaResolverAccount::AtticaResolverAccount( const QString& accountId ) } -AtticaResolverAccount::AtticaResolverAccount( const QString& accountId, const QString& path, const QString& atticaId ) - : ResolverAccount( accountId, path ) +AtticaResolverAccount::AtticaResolverAccount( const QString& accountId, const QString& path, const QString& atticaId, const QVariantHash& initialConfiguration ) + : ResolverAccount( accountId, path, initialConfiguration ) , m_atticaId( atticaId ) { QVariantHash conf = configuration(); diff --git a/src/libtomahawk/accounts/ResolverAccount.h b/src/libtomahawk/accounts/ResolverAccount.h index 9f25f2ade1..5906aad4cb 100644 --- a/src/libtomahawk/accounts/ResolverAccount.h +++ b/src/libtomahawk/accounts/ResolverAccount.h @@ -133,7 +133,7 @@ private slots: void loadIcon(); private: // Created by factory, when user installs a new resolver - AtticaResolverAccount( const QString& accountId, const QString& path, const QString& atticaId ); + AtticaResolverAccount( const QString& accountId, const QString& path, const QString& atticaId, const QVariantHash& initialConfiguration = QVariantHash() ); void init(); diff --git a/src/libtomahawk/resolvers/QtScriptResolver.cpp b/src/libtomahawk/resolvers/QtScriptResolver.cpp index a938d3abad..2347b5a28b 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.cpp +++ b/src/libtomahawk/resolvers/QtScriptResolver.cpp @@ -607,13 +607,14 @@ ScriptEngine::javaScriptConsoleMessage( const QString& message, int lineNumber, } -QtScriptResolver::QtScriptResolver( const QString& scriptPath ) +QtScriptResolver::QtScriptResolver( const QString& scriptPath, const QStringList& additionalScriptPaths ) : Tomahawk::ExternalResolverGui( scriptPath ) , m_ready( false ) , m_stopped( true ) , m_error( Tomahawk::ExternalResolver::NoError ) , m_resolverHelper( new QtScriptResolverHelper( scriptPath, this ) ) , m_signalMapper( new QSignalMapper(this) ) + , m_requiredScriptPaths( additionalScriptPaths ) { tLog() << Q_FUNC_INFO << "Loading JS resolver:" << scriptPath; @@ -646,14 +647,14 @@ QtScriptResolver::~QtScriptResolver() } -Tomahawk::ExternalResolver* QtScriptResolver::factory( const QString& scriptPath ) +Tomahawk::ExternalResolver* QtScriptResolver::factory( const QString& scriptPath, const QStringList& additionalScriptPaths ) { ExternalResolver* res = 0; const QFileInfo fi( scriptPath ); if ( fi.suffix() == "js" || fi.suffix() == "script" ) { - res = new QtScriptResolver( scriptPath ); + res = new QtScriptResolver( scriptPath, additionalScriptPaths ); tLog() << Q_FUNC_INFO << scriptPath << "Loaded."; } @@ -705,6 +706,21 @@ QtScriptResolver::init() m_engine->mainFrame()->evaluateJavaScript( jslib.readAll() ); jslib.close(); + // add resolver dependencies, if any + foreach ( QString s, m_requiredScriptPaths ) + { + QFile reqFile( s ); + if( !reqFile.open( QIODevice::ReadOnly ) ) + { + qWarning() << "Failed to read contents of file:" << s << reqFile.errorString(); + return; + } + const QByteArray reqContents = reqFile.readAll(); + + m_engine->setScriptPath( s ); + m_engine->mainFrame()->evaluateJavaScript( reqContents ); + } + // add resolver m_engine->setScriptPath( filePath() ); m_engine->mainFrame()->evaluateJavaScript( scriptContents ); diff --git a/src/libtomahawk/resolvers/QtScriptResolver.h b/src/libtomahawk/resolvers/QtScriptResolver.h index fcf3c399ef..4035850bfb 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.h +++ b/src/libtomahawk/resolvers/QtScriptResolver.h @@ -171,9 +171,9 @@ Q_OBJECT friend class ::QtScriptResolverHelper; public: - explicit QtScriptResolver( const QString& scriptPath ); + explicit QtScriptResolver( const QString& scriptPath, const QStringList& additionalScriptPaths = QStringList() ); virtual ~QtScriptResolver(); - static ExternalResolver* factory( const QString& scriptPath ); + static ExternalResolver* factory( const QString& scriptPath, const QStringList& additionalScriptPaths = QStringList() ); virtual Capabilities capabilities() const { return m_capabilities; } @@ -246,6 +246,7 @@ private slots: QtScriptResolverHelper* m_resolverHelper; QPointer< AccountConfigWidget > m_configWidget; QList< QVariant > m_dataWidgets; + QStringList m_requiredScriptPaths; }; #endif // QTSCRIPTRESOLVER_H diff --git a/src/libtomahawk/resolvers/ScriptResolver.cpp b/src/libtomahawk/resolvers/ScriptResolver.cpp index 1df21ba09e..3561f4f91a 100644 --- a/src/libtomahawk/resolvers/ScriptResolver.cpp +++ b/src/libtomahawk/resolvers/ScriptResolver.cpp @@ -96,8 +96,10 @@ ScriptResolver::~ScriptResolver() Tomahawk::ExternalResolver* -ScriptResolver::factory( const QString& exe ) +ScriptResolver::factory( const QString& exe, const QStringList& unused ) { + Q_UNUSED( unused ) + ExternalResolver* res = 0; const QFileInfo fi( exe ); diff --git a/src/libtomahawk/resolvers/ScriptResolver.h b/src/libtomahawk/resolvers/ScriptResolver.h index 14372a6698..0e0de460f0 100644 --- a/src/libtomahawk/resolvers/ScriptResolver.h +++ b/src/libtomahawk/resolvers/ScriptResolver.h @@ -40,7 +40,7 @@ Q_OBJECT public: explicit ScriptResolver( const QString& exe ); virtual ~ScriptResolver(); - static ExternalResolver* factory( const QString& exe ); + static ExternalResolver* factory( const QString& exe, const QStringList& ); virtual QString name() const { return m_name; } virtual QPixmap icon() const { return m_icon; } From 479e21e4df7dac9bc2b20cc43c8b3170181a35b9 Mon Sep 17 00:00:00 2001 From: ddqd Date: Sat, 16 Mar 2013 10:46:10 +0400 Subject: [PATCH 47/76] fix typing error on ru-translation --- lang/tomahawk_ru.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lang/tomahawk_ru.ts b/lang/tomahawk_ru.ts index 2de6c5ed30..d99f18374a 100644 --- a/lang/tomahawk_ru.ts +++ b/lang/tomahawk_ru.ts @@ -467,7 +467,7 @@ connect and stream from you? Don't send - Не отплавлять + Не отправлять From 942f13934c9da148196cbbcdbca127895c40dfd2 Mon Sep 17 00:00:00 2001 From: Teo Mrnjavac Date: Sat, 16 Mar 2013 16:36:04 +0100 Subject: [PATCH 48/76] Show resolver version for bundles, revision for packaged bundles. --- src/libtomahawk/accounts/Account.h | 1 + src/libtomahawk/accounts/AccountDelegate.cpp | 17 +++++++++++++++++ src/libtomahawk/accounts/AccountModel.cpp | 2 ++ src/libtomahawk/accounts/ResolverAccount.cpp | 17 +++++++++++++++++ src/libtomahawk/accounts/ResolverAccount.h | 1 + src/libtomahawk/utils/TomahawkUtils.h | 1 + src/libtomahawk/utils/TomahawkUtilsGui.cpp | 3 +++ 7 files changed, 42 insertions(+) diff --git a/src/libtomahawk/accounts/Account.h b/src/libtomahawk/accounts/Account.h index 54b6db6eca..5bbc3aee6f 100644 --- a/src/libtomahawk/accounts/Account.h +++ b/src/libtomahawk/accounts/Account.h @@ -90,6 +90,7 @@ class DLLEXPORT Account : public QObject #endif virtual QString description() const { return QString(); } virtual QString author() const { return QString(); } + virtual QString version() const { return QString(); } virtual void saveConfig() {} // called when the widget has been edited. save values from config widget, call sync() to write to disk account generic settings diff --git a/src/libtomahawk/accounts/AccountDelegate.cpp b/src/libtomahawk/accounts/AccountDelegate.cpp index 2ca7d3e1ed..be0306e96b 100644 --- a/src/libtomahawk/accounts/AccountDelegate.cpp +++ b/src/libtomahawk/accounts/AccountDelegate.cpp @@ -371,6 +371,23 @@ AccountDelegate::paint ( QPainter* painter, const QStyleOptionViewItem& option, painter->drawText( countRect, Qt::AlignLeft, count ); // runningEdge = authorRect.x(); } + else //no rating, it's not attica, let's show other stuff... + { + QString versionString = index.data( AccountModel::VersionRole ).toString(); + + if ( !versionString.isEmpty() ) + { + int runningEdge = textRect.left(); + int pkgTop = runningBottom + PADDING; + int h = painter->fontMetrics().height(); + + QRect pkgRect( runningEdge, pkgTop, h, h ); + painter->drawPixmap( pkgRect, TomahawkUtils::defaultPixmap( TomahawkUtils::ResolverBundle, TomahawkUtils::Original, pkgRect.size() ) ); + + QRect textRect( runningEdge + PADDING + h, pkgTop, painter->fontMetrics().width( versionString ), h ); + painter->drawText( textRect, Qt::AlignLeft, versionString ); + } + } // Title and description! return; diff --git a/src/libtomahawk/accounts/AccountModel.cpp b/src/libtomahawk/accounts/AccountModel.cpp index 637ff55a15..5c81caac47 100644 --- a/src/libtomahawk/accounts/AccountModel.cpp +++ b/src/libtomahawk/accounts/AccountModel.cpp @@ -342,6 +342,8 @@ AccountModel::data( const QModelIndex& index, int role ) const : acct->description(); case AuthorRole: return acct->author(); + case VersionRole: + return acct->version(); case Qt::CheckStateRole: return acct->enabled() ? Qt::Checked : Qt::Unchecked; case AccountData: diff --git a/src/libtomahawk/accounts/ResolverAccount.cpp b/src/libtomahawk/accounts/ResolverAccount.cpp index a3591caea3..83d048c9dd 100644 --- a/src/libtomahawk/accounts/ResolverAccount.cpp +++ b/src/libtomahawk/accounts/ResolverAccount.cpp @@ -154,6 +154,12 @@ ResolverAccountFactory::metadataFromJsonFile( const QString& path ) result[ "scripts" ] = scripts; } } + if ( !variant[ "version" ].isNull() ) + result[ "version" ] = variant[ "version" ]; + if ( !variant[ "revision" ].isNull() ) + result[ "revision" ] = variant[ "revision" ]; + if ( !variant[ "timestamp" ].isNull() ) + result[ "timestamp" ] = variant[ "timestamp" ]; } //TODO: correct baseName and rename directory maybe? } @@ -354,6 +360,17 @@ ResolverAccount::author() const } +QString +ResolverAccount::version() const +{ + QString versionString = configuration().value( "version" ).toString(); + QString build = configuration().value( "revision" ).toString(); + if ( !build.isEmpty() ) + return versionString + "-" + build; + return versionString; +} + + /// AtticaResolverAccount AtticaResolverAccount::AtticaResolverAccount( const QString& accountId ) diff --git a/src/libtomahawk/accounts/ResolverAccount.h b/src/libtomahawk/accounts/ResolverAccount.h index 5906aad4cb..f86b6225f5 100644 --- a/src/libtomahawk/accounts/ResolverAccount.h +++ b/src/libtomahawk/accounts/ResolverAccount.h @@ -86,6 +86,7 @@ class DLLEXPORT ResolverAccount : public Account virtual QPixmap icon() const; virtual QString description() const; virtual QString author() const; + virtual QString version() const; // Not relevant virtual SipPlugin* sipPlugin() { return 0; } diff --git a/src/libtomahawk/utils/TomahawkUtils.h b/src/libtomahawk/utils/TomahawkUtils.h index 70814a6e71..e2faee66fb 100644 --- a/src/libtomahawk/utils/TomahawkUtils.h +++ b/src/libtomahawk/utils/TomahawkUtils.h @@ -121,6 +121,7 @@ namespace TomahawkUtils StarHovered, SipPluginOnline, SipPluginOffline, + ResolverBundle, Invalid }; diff --git a/src/libtomahawk/utils/TomahawkUtilsGui.cpp b/src/libtomahawk/utils/TomahawkUtilsGui.cpp index ef19cfc8d3..28547344ea 100644 --- a/src/libtomahawk/utils/TomahawkUtilsGui.cpp +++ b/src/libtomahawk/utils/TomahawkUtilsGui.cpp @@ -710,6 +710,9 @@ defaultPixmap( ImageType type, ImageMode mode, const QSize& size ) case SoundcloudIcon: pixmap = ImageRegistry::instance()->pixmap( RESPATH "images/soundcloud.svg", size ); break; + case ResolverBundle: + pixmap = ImageRegistry::instance()->pixmap( RESPATH "images/drop-all-songs.svg", size ); + break; default: break; From 385fc46f5c1c4433e74490392c6525fb5378a794 Mon Sep 17 00:00:00 2001 From: Teo Mrnjavac Date: Sun, 17 Mar 2013 13:47:26 +0100 Subject: [PATCH 49/76] Remove bundle directory on account removal. --- src/libtomahawk/accounts/AccountManager.cpp | 4 +++ src/libtomahawk/accounts/ResolverAccount.cpp | 27 +++++++++++++++++--- src/libtomahawk/accounts/ResolverAccount.h | 2 ++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/libtomahawk/accounts/AccountManager.cpp b/src/libtomahawk/accounts/AccountManager.cpp index 12baaffa31..8b20bd7c5c 100644 --- a/src/libtomahawk/accounts/AccountManager.cpp +++ b/src/libtomahawk/accounts/AccountManager.cpp @@ -351,6 +351,10 @@ AccountManager::removeAccount( Account* account ) m_accountsByAccountType[ type ] = accounts; } + ResolverAccount* raccount = qobject_cast< ResolverAccount* >( account ); + if ( raccount ) + raccount->removeBundle(); + TomahawkSettings::instance()->removeAccount( account->accountId() ); account->removeFromConfig(); diff --git a/src/libtomahawk/accounts/ResolverAccount.cpp b/src/libtomahawk/accounts/ResolverAccount.cpp index 83d048c9dd..0062f9ec31 100644 --- a/src/libtomahawk/accounts/ResolverAccount.cpp +++ b/src/libtomahawk/accounts/ResolverAccount.cpp @@ -33,6 +33,8 @@ #include #include +#define MANUALRESOLVERS_DIR "manualresolvers" + using namespace Tomahawk; using namespace Accounts; @@ -85,9 +87,10 @@ ResolverAccountFactory::createFromPath( const QString& path, const QString& fact if ( pathInfo.suffix() == "axe" ) { + QString uniqueName = uuid(); QDir dir( TomahawkUtils::extractScriptPayload( pathInfo.filePath(), - pathInfo.completeBaseName(), - "manualresolvers" ) ); + uniqueName, + MANUALRESOLVERS_DIR ) ); if ( !( dir.exists() && dir.isReadable() ) ) //decompression fubar return 0; @@ -95,9 +98,10 @@ ResolverAccountFactory::createFromPath( const QString& path, const QString& fact return 0; QString metadataFilePath = dir.absoluteFilePath( "metadata.json" ); - configuration = metadataFromJsonFile( metadataFilePath ); + realPath = configuration[ "path" ].toString(); + configuration[ "bundleDir" ] = uniqueName; if ( realPath.isEmpty() ) return 0; } @@ -133,6 +137,7 @@ ResolverAccountFactory::metadataFromJsonFile( const QString& path ) if ( ok ) { + result[ "pluginName" ] = variant[ "pluginName" ]; result[ "author" ] = variant[ "author" ]; result[ "description" ] = variant[ "description" ]; if ( !variant[ "manifest" ].isNull() ) @@ -371,6 +376,22 @@ ResolverAccount::version() const } +void +ResolverAccount::removeBundle() +{ + QString bundleDir = configuration()[ "bundleDir" ].toString(); + if ( bundleDir.isEmpty() ) + return; + + QString expectedPath = TomahawkUtils::appDataDir().absoluteFilePath( QString( "%1/%2" ).arg( MANUALRESOLVERS_DIR ).arg( bundleDir ) ); + QFileInfo fi( expectedPath ); + if ( fi.exists() && fi.isDir() && fi.isWritable() ) + { + TomahawkUtils::removeDirectory( expectedPath ); + } +} + + /// AtticaResolverAccount AtticaResolverAccount::AtticaResolverAccount( const QString& accountId ) diff --git a/src/libtomahawk/accounts/ResolverAccount.h b/src/libtomahawk/accounts/ResolverAccount.h index f86b6225f5..a002c0c06a 100644 --- a/src/libtomahawk/accounts/ResolverAccount.h +++ b/src/libtomahawk/accounts/ResolverAccount.h @@ -93,6 +93,8 @@ class DLLEXPORT ResolverAccount : public Account virtual Tomahawk::InfoSystem::InfoPluginPtr infoPlugin() { return Tomahawk::InfoSystem::InfoPluginPtr(); } virtual QWidget* aclWidget() { return 0; } + virtual void removeBundle(); + private slots: void resolverChanged(); From 14d5833a93e86d93b7c882b1490d40960c5ddcfa Mon Sep 17 00:00:00 2001 From: Teo Mrnjavac Date: Sun, 17 Mar 2013 13:51:15 +0100 Subject: [PATCH 50/76] Obsolete TODO is obsolete. --- src/libtomahawk/accounts/ResolverAccount.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libtomahawk/accounts/ResolverAccount.cpp b/src/libtomahawk/accounts/ResolverAccount.cpp index 0062f9ec31..9c3fa2d641 100644 --- a/src/libtomahawk/accounts/ResolverAccount.cpp +++ b/src/libtomahawk/accounts/ResolverAccount.cpp @@ -166,7 +166,6 @@ ResolverAccountFactory::metadataFromJsonFile( const QString& path ) if ( !variant[ "timestamp" ].isNull() ) result[ "timestamp" ] = variant[ "timestamp" ]; } - //TODO: correct baseName and rename directory maybe? } return result; } From 05ee8cd2d82522ef59274a74df83cc6769d77bfa Mon Sep 17 00:00:00 2001 From: Lasse Liehu Date: Tue, 19 Mar 2013 20:13:04 +0200 Subject: [PATCH 51/76] Add context for placeholders in 3 UI messages added recently --- src/infoplugins/linux/fdonotify/FdoNotifyPlugin.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/infoplugins/linux/fdonotify/FdoNotifyPlugin.cpp b/src/infoplugins/linux/fdonotify/FdoNotifyPlugin.cpp index 8825dfcc80..389b073342 100644 --- a/src/infoplugins/linux/fdonotify/FdoNotifyPlugin.cpp +++ b/src/infoplugins/linux/fdonotify/FdoNotifyPlugin.cpp @@ -190,9 +190,9 @@ FdoNotifyPlugin::nowPlaying( const QVariant& input ) // Remark: If using xml-based markup in notifications, the supplied strings need to be escaped. QString album; if ( !hash[ "album" ].isEmpty() ) - album = tr( "
on %1" ).arg( Qt::escape( hash[ "album" ] ) ); + album = tr( "
on %1", "%1 is an album name" ).arg( Qt::escape( hash[ "album" ] ) ); - messageText = tr( "%1
by %2%3." ) + messageText = tr( "%1
by %2%3.", "%1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing" ) .arg( Qt::escape( hash[ "title" ] ) ) .arg( Qt::escape( hash[ "artist" ] ) ) .arg( album ); @@ -201,9 +201,9 @@ FdoNotifyPlugin::nowPlaying( const QVariant& input ) { QString album; if ( !hash[ "album" ].isEmpty() ) - album = QString( " %1" ).arg( tr( "on \"%1\"" ).arg( hash[ "album" ] ) ); + album = QString( " %1" ).arg( tr( "on \"%1\"", "%1 is an album name" ).arg( hash[ "album" ] ) ); - messageText = tr( "\"%1\" by %2%3." ) + messageText = tr( "\"%1\" by %2%3.", "%1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing" ) .arg( hash[ "title" ] ) .arg( hash[ "artist" ] ) .arg( album ); From 4523231a85de5f5eff6726c9e125de084db97479 Mon Sep 17 00:00:00 2001 From: Tomahawk CI Date: Wed, 20 Mar 2013 01:16:28 +0100 Subject: [PATCH 52/76] Automatic merge of Transifex translations --- lang/tomahawk_ar.ts | 24 +++++++++++++++++++----- lang/tomahawk_bg.ts | 24 +++++++++++++++++++----- lang/tomahawk_bn_IN.ts | 20 +++++++++++++++++--- lang/tomahawk_ca.ts | 24 +++++++++++++++++++----- lang/tomahawk_ca@valencia.ts | 24 +++++++++++++++++++----- lang/tomahawk_cs.ts | 24 +++++++++++++++++++----- lang/tomahawk_da.ts | 20 +++++++++++++++++--- lang/tomahawk_de.ts | 24 +++++++++++++++++++----- lang/tomahawk_el.ts | 20 +++++++++++++++++--- lang/tomahawk_en.ts | 22 ++++++++++++++++++---- lang/tomahawk_es.ts | 24 +++++++++++++++++++----- lang/tomahawk_fi.ts | 24 +++++++++++++++++++----- lang/tomahawk_fr.ts | 24 +++++++++++++++++++----- lang/tomahawk_gl.ts | 24 +++++++++++++++++++----- lang/tomahawk_hi_IN.ts | 20 +++++++++++++++++--- lang/tomahawk_hu.ts | 20 +++++++++++++++++--- lang/tomahawk_it.ts | 24 +++++++++++++++++++----- lang/tomahawk_ja.ts | 24 +++++++++++++++++++----- lang/tomahawk_lt.ts | 24 +++++++++++++++++++----- lang/tomahawk_pl.ts | 24 +++++++++++++++++++----- lang/tomahawk_pt_BR.ts | 24 +++++++++++++++++++----- lang/tomahawk_ru.ts | 24 +++++++++++++++++++----- lang/tomahawk_sv.ts | 24 +++++++++++++++++++----- lang/tomahawk_tr.ts | 20 +++++++++++++++++--- lang/tomahawk_zh_CN.ts | 22 ++++++++++++++++++---- lang/tomahawk_zh_TW.ts | 20 +++++++++++++++++--- 26 files changed, 478 insertions(+), 114 deletions(-) diff --git a/lang/tomahawk_ar.ts b/lang/tomahawk_ar.ts index ce49bec7f8..4a40cf8a2e 100644 --- a/lang/tomahawk_ar.ts +++ b/lang/tomahawk_ar.ts @@ -3114,14 +3114,28 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::FdoNotifyPlugin - - Tomahawk is playing "%1" by %2%3. - توماهوك يلعب "%1" ل%2%3. + + <br /><i>on</i> %1 + %1 is an album name + - + + %1<br /><i>by</i> %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + + + + on "%1" - على "%1" + %1 is an album name + + + + + "%1" by %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + diff --git a/lang/tomahawk_bg.ts b/lang/tomahawk_bg.ts index 77bbbd3e84..63c03d0477 100644 --- a/lang/tomahawk_bg.ts +++ b/lang/tomahawk_bg.ts @@ -3127,14 +3127,28 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::FdoNotifyPlugin - - Tomahawk is playing "%1" by %2%3. - Tomahawk възпроизвежда "%1" от %2%3 + + <br /><i>on</i> %1 + %1 is an album name + + + + + %1<br /><i>by</i> %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + - + on "%1" - от "%1" + %1 is an album name + + + + + "%1" by %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + diff --git a/lang/tomahawk_bn_IN.ts b/lang/tomahawk_bn_IN.ts index b6e2b58697..bd418d14da 100644 --- a/lang/tomahawk_bn_IN.ts +++ b/lang/tomahawk_bn_IN.ts @@ -3101,13 +3101,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::FdoNotifyPlugin - - Tomahawk is playing "%1" by %2%3. + + <br /><i>on</i> %1 + %1 is an album name - + + %1<br /><i>by</i> %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + + + + on "%1" + %1 is an album name + + + + + "%1" by %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing diff --git a/lang/tomahawk_ca.ts b/lang/tomahawk_ca.ts index b1a862db99..1077f0b3fe 100644 --- a/lang/tomahawk_ca.ts +++ b/lang/tomahawk_ca.ts @@ -3115,14 +3115,28 @@ Intenteu ajustar els filtres per reproduir noves cançons. Tomahawk::InfoSystem::FdoNotifyPlugin - - Tomahawk is playing "%1" by %2%3. - Tomahawk està reproduint "%1" de %2%3. + + <br /><i>on</i> %1 + %1 is an album name + + + + + %1<br /><i>by</i> %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + - + on "%1" - a "%1" + %1 is an album name + + + + + "%1" by %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + diff --git a/lang/tomahawk_ca@valencia.ts b/lang/tomahawk_ca@valencia.ts index bead97d137..73dbb060c7 100644 --- a/lang/tomahawk_ca@valencia.ts +++ b/lang/tomahawk_ca@valencia.ts @@ -3115,14 +3115,28 @@ Intenteu ajustar els filtres per reproduir noves cançons. Tomahawk::InfoSystem::FdoNotifyPlugin - - Tomahawk is playing "%1" by %2%3. - Tomahawk està reproduint "%1" de %2%3. + + <br /><i>on</i> %1 + %1 is an album name + + + + + %1<br /><i>by</i> %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + - + on "%1" - a "%1" + %1 is an album name + + + + + "%1" by %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + diff --git a/lang/tomahawk_cs.ts b/lang/tomahawk_cs.ts index 0614d1994c..a67ba36424 100644 --- a/lang/tomahawk_cs.ts +++ b/lang/tomahawk_cs.ts @@ -3113,14 +3113,28 @@ Zkuste vyladit filtry pro nové písně. Tomahawk::InfoSystem::FdoNotifyPlugin - - Tomahawk is playing "%1" by %2%3. - Tomahawk hraje "%1" od %2%3. + + <br /><i>on</i> %1 + %1 is an album name + - + + %1<br /><i>by</i> %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + + + + on "%1" - na "%1" + %1 is an album name + + + + + "%1" by %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + diff --git a/lang/tomahawk_da.ts b/lang/tomahawk_da.ts index f5c8c0a29e..96e60bb123 100644 --- a/lang/tomahawk_da.ts +++ b/lang/tomahawk_da.ts @@ -3103,13 +3103,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::FdoNotifyPlugin - - Tomahawk is playing "%1" by %2%3. + + <br /><i>on</i> %1 + %1 is an album name - + + %1<br /><i>by</i> %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + + + + on "%1" + %1 is an album name + + + + + "%1" by %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing diff --git a/lang/tomahawk_de.ts b/lang/tomahawk_de.ts index df9a665949..a08ab0be05 100644 --- a/lang/tomahawk_de.ts +++ b/lang/tomahawk_de.ts @@ -3108,14 +3108,28 @@ Versuch die Filter anzupassen für neue Lieder. Tomahawk::InfoSystem::FdoNotifyPlugin - - Tomahawk is playing "%1" by %2%3. - Tomahawk spielt "%1" von %2%3. + + <br /><i>on</i> %1 + %1 is an album name + + + + + %1<br /><i>by</i> %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + - + on "%1" - auf "%1" + %1 is an album name + + + + + "%1" by %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + diff --git a/lang/tomahawk_el.ts b/lang/tomahawk_el.ts index 3fdc3ab047..cd88ec7cef 100644 --- a/lang/tomahawk_el.ts +++ b/lang/tomahawk_el.ts @@ -3109,13 +3109,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::FdoNotifyPlugin - - Tomahawk is playing "%1" by %2%3. + + <br /><i>on</i> %1 + %1 is an album name - + + %1<br /><i>by</i> %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + + + + on "%1" + %1 is an album name + + + + + "%1" by %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing diff --git a/lang/tomahawk_en.ts b/lang/tomahawk_en.ts index 7d89975732..a71abd63d7 100644 --- a/lang/tomahawk_en.ts +++ b/lang/tomahawk_en.ts @@ -3116,15 +3116,29 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::FdoNotifyPlugin - - Tomahawk is playing "%1" by %2%3. - Tomahawk is playing "%1" by %2%3. + + <br /><i>on</i> %1 + %1 is an album name + <br /><i>on</i> %1 - + + %1<br /><i>by</i> %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + %1<br /><i>by</i> %2%3. + + + on "%1" + %1 is an album name on "%1" + + + "%1" by %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + "%1" by %2%3. + Tomahawk::InfoSystem::LastFmInfoPlugin diff --git a/lang/tomahawk_es.ts b/lang/tomahawk_es.ts index 76bfeeadf4..ca50078a11 100644 --- a/lang/tomahawk_es.ts +++ b/lang/tomahawk_es.ts @@ -3116,14 +3116,28 @@ Intente ajustar los filtros para reproducir nuevas canciones. Tomahawk::InfoSystem::FdoNotifyPlugin - - Tomahawk is playing "%1" by %2%3. - Tomahawk está reproduciendo «%1» de %2%3. + + <br /><i>on</i> %1 + %1 is an album name + + + + + %1<br /><i>by</i> %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + - + on "%1" - en «%1» + %1 is an album name + + + + + "%1" by %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + diff --git a/lang/tomahawk_fi.ts b/lang/tomahawk_fi.ts index 4b416a4d14..4eace57b4c 100644 --- a/lang/tomahawk_fi.ts +++ b/lang/tomahawk_fi.ts @@ -3119,14 +3119,28 @@ Koeta säätää suodattimia saadaksesi uuden joukon kappaleita kuunneltavaksi.< Tomahawk::InfoSystem::FdoNotifyPlugin - - Tomahawk is playing "%1" by %2%3. - Tomahawk soittaa artistin %2 kappaletta ”%1”%3. + + <br /><i>on</i> %1 + %1 is an album name + <br /><i>albumilla</i> %1 - + + %1<br /><i>by</i> %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + %1<br /><i>artistilta</i> %2%3. + + + on "%1" - albumilta ”%1” + %1 is an album name + albumilla ”%1” + + + + "%1" by %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + ”%1” artistilta %2%3. diff --git a/lang/tomahawk_fr.ts b/lang/tomahawk_fr.ts index 56b6552364..588c498161 100644 --- a/lang/tomahawk_fr.ts +++ b/lang/tomahawk_fr.ts @@ -3113,14 +3113,28 @@ Essayez de changer les filtres pour avoir de nouveaux morceaux à jouer. Tomahawk::InfoSystem::FdoNotifyPlugin - - Tomahawk is playing "%1" by %2%3. - Tomahawk joue "%1" par %2%3. + + <br /><i>on</i> %1 + %1 is an album name + + + + + %1<br /><i>by</i> %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + - + on "%1" - sur "%1" + %1 is an album name + + + + + "%1" by %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + diff --git a/lang/tomahawk_gl.ts b/lang/tomahawk_gl.ts index 261dda8f3f..dd8f99f313 100644 --- a/lang/tomahawk_gl.ts +++ b/lang/tomahawk_gl.ts @@ -3115,14 +3115,28 @@ Proba a trocar os filtros para ter outra lista música para escoitar. Tomahawk::InfoSystem::FdoNotifyPlugin - - Tomahawk is playing "%1" by %2%3. - Tomahawk está reproducindo «%1» por %2 %3. + + <br /><i>on</i> %1 + %1 is an album name + + + + + %1<br /><i>by</i> %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + - + on "%1" - en «%1» + %1 is an album name + + + + + "%1" by %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + diff --git a/lang/tomahawk_hi_IN.ts b/lang/tomahawk_hi_IN.ts index 7cd6ec4ee3..77b7c7d9d5 100644 --- a/lang/tomahawk_hi_IN.ts +++ b/lang/tomahawk_hi_IN.ts @@ -3101,13 +3101,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::FdoNotifyPlugin - - Tomahawk is playing "%1" by %2%3. + + <br /><i>on</i> %1 + %1 is an album name - + + %1<br /><i>by</i> %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + + + + on "%1" + %1 is an album name + + + + + "%1" by %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing diff --git a/lang/tomahawk_hu.ts b/lang/tomahawk_hu.ts index 8026b36a47..2d4f1206f4 100644 --- a/lang/tomahawk_hu.ts +++ b/lang/tomahawk_hu.ts @@ -3101,13 +3101,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::FdoNotifyPlugin - - Tomahawk is playing "%1" by %2%3. + + <br /><i>on</i> %1 + %1 is an album name - + + %1<br /><i>by</i> %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + + + + on "%1" + %1 is an album name + + + + + "%1" by %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing diff --git a/lang/tomahawk_it.ts b/lang/tomahawk_it.ts index 6e07fc5fe0..9ced806e79 100644 --- a/lang/tomahawk_it.ts +++ b/lang/tomahawk_it.ts @@ -3101,14 +3101,28 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::FdoNotifyPlugin - - Tomahawk is playing "%1" by %2%3. - Tomahawk sta riproducendo "%1" di %2%3. + + <br /><i>on</i> %1 + %1 is an album name + + + + + %1<br /><i>by</i> %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + - + on "%1" - su "%1" + %1 is an album name + + + + + "%1" by %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + diff --git a/lang/tomahawk_ja.ts b/lang/tomahawk_ja.ts index c737a4b816..1b5f7da950 100644 --- a/lang/tomahawk_ja.ts +++ b/lang/tomahawk_ja.ts @@ -3113,14 +3113,28 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::FdoNotifyPlugin - - Tomahawk is playing "%1" by %2%3. - Tomahawkが%2の%3の「%1」を再生しています + + <br /><i>on</i> %1 + %1 is an album name + + + + + %1<br /><i>by</i> %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + - + on "%1" - 「%1」 + %1 is an album name + + + + + "%1" by %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + diff --git a/lang/tomahawk_lt.ts b/lang/tomahawk_lt.ts index 630f72d1ff..acfcf7e58d 100644 --- a/lang/tomahawk_lt.ts +++ b/lang/tomahawk_lt.ts @@ -3101,14 +3101,28 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::FdoNotifyPlugin - - Tomahawk is playing "%1" by %2%3. - Tomahawk groja "%1" atliekamą %2%3. + + <br /><i>on</i> %1 + %1 is an album name + + + + + %1<br /><i>by</i> %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + - + on "%1" - iš albumo "%1" + %1 is an album name + + + + + "%1" by %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + diff --git a/lang/tomahawk_pl.ts b/lang/tomahawk_pl.ts index 8aba862b83..2f034576e0 100644 --- a/lang/tomahawk_pl.ts +++ b/lang/tomahawk_pl.ts @@ -3110,14 +3110,28 @@ Spróbuj poprawić filtry aby uzyskać nowy zestaw piosenek do odtworzenia. Tomahawk::InfoSystem::FdoNotifyPlugin - - Tomahawk is playing "%1" by %2%3. - Tomahawk odtwarza "%1" wykonawcy %2%3. + + <br /><i>on</i> %1 + %1 is an album name + + + + + %1<br /><i>by</i> %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + - + on "%1" - z "%1" + %1 is an album name + + + + + "%1" by %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + diff --git a/lang/tomahawk_pt_BR.ts b/lang/tomahawk_pt_BR.ts index 777c80c187..82a19dad74 100644 --- a/lang/tomahawk_pt_BR.ts +++ b/lang/tomahawk_pt_BR.ts @@ -3110,14 +3110,28 @@ Tente ajustar os filtros para ouvir um novo conjunto de músicas. Tomahawk::InfoSystem::FdoNotifyPlugin - - Tomahawk is playing "%1" by %2%3. - Tomahawk está tocando "%1" de %2%3. + + <br /><i>on</i> %1 + %1 is an album name + + + + + %1<br /><i>by</i> %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + - + on "%1" - em "%1" + %1 is an album name + + + + + "%1" by %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + diff --git a/lang/tomahawk_ru.ts b/lang/tomahawk_ru.ts index d99f18374a..077c366c6e 100644 --- a/lang/tomahawk_ru.ts +++ b/lang/tomahawk_ru.ts @@ -3117,14 +3117,28 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::FdoNotifyPlugin - - Tomahawk is playing "%1" by %2%3. - Tomahawk играет "%1" %2%3. + + <br /><i>on</i> %1 + %1 is an album name + + + + + %1<br /><i>by</i> %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + - + on "%1" - "%1" + %1 is an album name + + + + + "%1" by %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + diff --git a/lang/tomahawk_sv.ts b/lang/tomahawk_sv.ts index 6b5f83a86a..8298a61e78 100644 --- a/lang/tomahawk_sv.ts +++ b/lang/tomahawk_sv.ts @@ -3114,14 +3114,28 @@ Försök att ändra i filtrerna för att få en ny låtlista Tomahawk::InfoSystem::FdoNotifyPlugin - - Tomahawk is playing "%1" by %2%3. - Tomahawk spelar "%1" by %2%3. + + <br /><i>on</i> %1 + %1 is an album name + + + + + %1<br /><i>by</i> %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + - + on "%1" - på "%1" + %1 is an album name + + + + + "%1" by %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + diff --git a/lang/tomahawk_tr.ts b/lang/tomahawk_tr.ts index 79c4ef94c3..84e6401fb5 100644 --- a/lang/tomahawk_tr.ts +++ b/lang/tomahawk_tr.ts @@ -3101,13 +3101,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::FdoNotifyPlugin - - Tomahawk is playing "%1" by %2%3. + + <br /><i>on</i> %1 + %1 is an album name - + + %1<br /><i>by</i> %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + + + + on "%1" + %1 is an album name + + + + + "%1" by %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing diff --git a/lang/tomahawk_zh_CN.ts b/lang/tomahawk_zh_CN.ts index 22e955e89c..d0f0b74dce 100644 --- a/lang/tomahawk_zh_CN.ts +++ b/lang/tomahawk_zh_CN.ts @@ -3111,13 +3111,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::FdoNotifyPlugin - - Tomahawk is playing "%1" by %2%3. - Tomahawk 正在播放 %2%3 的 '%1'。 + + <br /><i>on</i> %1 + %1 is an album name + + + + + %1<br /><i>by</i> %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + - + on "%1" + %1 is an album name + + + + + "%1" by %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing diff --git a/lang/tomahawk_zh_TW.ts b/lang/tomahawk_zh_TW.ts index 06b59fa78c..c2a6add397 100644 --- a/lang/tomahawk_zh_TW.ts +++ b/lang/tomahawk_zh_TW.ts @@ -3101,13 +3101,27 @@ Try tweaking the filters for a new set of songs to play. Tomahawk::InfoSystem::FdoNotifyPlugin - - Tomahawk is playing "%1" by %2%3. + + <br /><i>on</i> %1 + %1 is an album name - + + %1<br /><i>by</i> %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing + + + + on "%1" + %1 is an album name + + + + + "%1" by %2%3. + %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing From 3e25d3d4022912976b706ba50210c423da8f7328 Mon Sep 17 00:00:00 2001 From: Teo Mrnjavac Date: Wed, 20 Mar 2013 21:42:25 +0100 Subject: [PATCH 53/76] Install resolver axes in dirs with human-readable name instead of uuid. --- src/libtomahawk/accounts/ResolverAccount.cpp | 61 ++++++++++++++++---- src/libtomahawk/accounts/ResolverAccount.h | 3 + 2 files changed, 54 insertions(+), 10 deletions(-) diff --git a/src/libtomahawk/accounts/ResolverAccount.cpp b/src/libtomahawk/accounts/ResolverAccount.cpp index 9c3fa2d641..049b098a03 100644 --- a/src/libtomahawk/accounts/ResolverAccount.cpp +++ b/src/libtomahawk/accounts/ResolverAccount.cpp @@ -76,6 +76,7 @@ ResolverAccountFactory::createFromPath( const QString& path, const QString& fact { QString metadataFilePath = dir.absoluteFilePath( "metadata.json" ); configuration = metadataFromJsonFile( metadataFilePath ); + expandPaths( dir, configuration ); } return new AtticaResolverAccount( generateId( factory ), path, pathInfo.baseName(), configuration ); } @@ -100,8 +101,35 @@ ResolverAccountFactory::createFromPath( const QString& path, const QString& fact QString metadataFilePath = dir.absoluteFilePath( "metadata.json" ); configuration = metadataFromJsonFile( metadataFilePath ); - realPath = configuration[ "path" ].toString(); configuration[ "bundleDir" ] = uniqueName; + + if ( !configuration[ "pluginName" ].isNull() && !configuration[ "pluginName" ].toString().isEmpty() ) + { + dir.cdUp(); + if ( !dir.cdUp() ) //we're in MANUALRESOLVERS_DIR + return 0; + + QString name = configuration[ "pluginName" ].toString(); + + QString namePath = dir.absoluteFilePath( name ); + QFileInfo npI( namePath ); + + if ( npI.exists() && npI.isDir() ) + { + TomahawkUtils::removeDirectory( namePath ); + } + + dir.rename( uniqueName, name ); + + configuration[ "bundleDir" ] = name; + + if ( !dir.cd( QString( "%1/content" ).arg( name ) ) ) //should work if it worked once + return 0; + } + + expandPaths( dir, configuration ); + + realPath = configuration[ "path" ].toString(); if ( realPath.isEmpty() ) return 0; } @@ -112,6 +140,7 @@ ResolverAccountFactory::createFromPath( const QString& path, const QString& fact { QString metadataFilePath = dir.absoluteFilePath( "metadata.json" ); configuration = metadataFromJsonFile( metadataFilePath ); + expandPaths( dir, configuration ); configuration[ "path" ] = realPath; //our initial path still overrides whatever the desktop file says } //else we just have empty metadata (legacy resolver without desktop file) @@ -145,18 +174,11 @@ ResolverAccountFactory::metadataFromJsonFile( const QString& path ) QVariantMap manifest = variant[ "manifest" ].toMap(); if ( !manifest[ "main" ].isNull() ) { - QFileInfo fi( path ); - result[ "path" ] = fi.absoluteDir().absoluteFilePath( manifest[ "main" ].toString() ); //this is our path to the JS + result[ "path" ] = manifest[ "main" ]; //this is our path to the main JS script } if ( !manifest[ "scripts" ].isNull() ) { - QStringList scripts; - foreach ( QString s, manifest[ "scripts" ].toStringList() ) - { - QFileInfo fi( path ); - scripts << fi.absoluteDir().absoluteFilePath( s ); - } - result[ "scripts" ] = scripts; + result[ "scripts" ] = manifest[ "scripts" ]; //any additional scripts to load before } } if ( !variant[ "version" ].isNull() ) @@ -171,6 +193,25 @@ ResolverAccountFactory::metadataFromJsonFile( const QString& path ) } +void +ResolverAccountFactory::expandPaths( const QDir& contentDir, QVariantHash& configuration ) +{ + if ( !configuration[ "path" ].isNull() ) + { + configuration[ "path" ] = contentDir.absoluteFilePath( configuration[ "path" ].toString() ); //this is our path to the JS + } + if ( !configuration[ "scripts" ].isNull() ) + { + QStringList scripts; + foreach ( QString s, configuration[ "scripts" ].toStringList() ) + { + scripts << contentDir.absoluteFilePath( s ); + } + configuration[ "scripts" ] = scripts; + } +} + + ResolverAccount::ResolverAccount( const QString& accountId ) : Account( accountId ) { diff --git a/src/libtomahawk/accounts/ResolverAccount.h b/src/libtomahawk/accounts/ResolverAccount.h index a002c0c06a..3c4b583394 100644 --- a/src/libtomahawk/accounts/ResolverAccount.h +++ b/src/libtomahawk/accounts/ResolverAccount.h @@ -25,6 +25,8 @@ #include +class QDir; + namespace Tomahawk { class ExternalResolverGui; @@ -55,6 +57,7 @@ class DLLEXPORT ResolverAccountFactory : public AccountFactory private: static QVariantHash metadataFromJsonFile( const QString& path ); + static void expandPaths( const QDir& contentDir, QVariantHash& configuration ); }; /** From 0b72a10f20460319981155a3398929eba624f753 Mon Sep 17 00:00:00 2001 From: Tomahawk CI Date: Fri, 22 Mar 2013 01:16:56 +0100 Subject: [PATCH 54/76] Automatic merge of Transifex translations --- lang/tomahawk_ar.ts | 8 ++++---- lang/tomahawk_sv.ts | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lang/tomahawk_ar.ts b/lang/tomahawk_ar.ts index 4a40cf8a2e..99235f06f4 100644 --- a/lang/tomahawk_ar.ts +++ b/lang/tomahawk_ar.ts @@ -3117,25 +3117,25 @@ Try tweaking the filters for a new set of songs to play. <br /><i>on</i> %1 %1 is an album name - + <br /><i>في</i> %1
%1<br /><i>by</i> %2%3. %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing - + %1<br /><i>من قبل</i> %2%3. on "%1" %1 is an album name - + في "%1" "%1" by %2%3. %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing - + "%1" من قبل %2%3. diff --git a/lang/tomahawk_sv.ts b/lang/tomahawk_sv.ts index 8298a61e78..19473cefad 100644 --- a/lang/tomahawk_sv.ts +++ b/lang/tomahawk_sv.ts @@ -1127,13 +1127,13 @@ ansluta och strömma från dig? A playlist you created %1. - En spellista du skapat &1. + En spellista du skapat %1. A playlist by %1, created %2. - En spellista av &1, skapad &2 + En spellista av %1, skapad %2 From ab6c2f85c68749eda0f43d0308ea75540d4cca21 Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Fri, 22 Mar 2013 08:33:48 +0100 Subject: [PATCH 55/76] Remove thirdparty KQoauth, not used anymore. --- src/libtomahawk/CMakeLists.txt | 8 - .../thirdparty/kqoauth/LGPL_EXCEPTION.txt | 22 - .../thirdparty/kqoauth/LICENSE.LGPL | 505 ------------ .../thirdparty/kqoauth/kqoauth2request.cpp | 61 -- .../thirdparty/kqoauth/kqoauth2request.h | 50 -- .../thirdparty/kqoauth/kqoauth2request_p.h | 14 - .../kqoauth/kqoauthauthreplyserver.cpp | 140 ---- .../kqoauth/kqoauthauthreplyserver.h | 52 -- .../kqoauth/kqoauthauthreplyserver_p.h | 53 -- .../thirdparty/kqoauth/kqoauthglobals.h | 52 -- .../thirdparty/kqoauth/kqoauthmanager.cpp | 729 ------------------ .../thirdparty/kqoauth/kqoauthmanager.h | 205 ----- .../thirdparty/kqoauth/kqoauthmanager_p.h | 80 -- .../thirdparty/kqoauth/kqoauthrequest.cpp | 625 --------------- .../thirdparty/kqoauth/kqoauthrequest.h | 157 ---- .../thirdparty/kqoauth/kqoauthrequest_1.cpp | 5 - .../thirdparty/kqoauth/kqoauthrequest_1.h | 12 - .../thirdparty/kqoauth/kqoauthrequest_p.h | 98 --- .../kqoauth/kqoauthrequest_xauth.cpp | 95 --- .../thirdparty/kqoauth/kqoauthrequest_xauth.h | 53 -- .../kqoauth/kqoauthrequest_xauth_p.h | 14 - .../thirdparty/kqoauth/kqoauthutils.cpp | 83 -- .../thirdparty/kqoauth/kqoauthutils.h | 37 - 23 files changed, 3150 deletions(-) delete mode 100644 src/libtomahawk/thirdparty/kqoauth/LGPL_EXCEPTION.txt delete mode 100644 src/libtomahawk/thirdparty/kqoauth/LICENSE.LGPL delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauth2request.cpp delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauth2request.h delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauth2request_p.h delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver.cpp delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver.h delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver_p.h delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthglobals.h delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.cpp delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.h delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthmanager_p.h delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthrequest.cpp delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthrequest.h delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_1.cpp delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_1.h delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_p.h delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth.cpp delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth.h delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth_p.h delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthutils.cpp delete mode 100644 src/libtomahawk/thirdparty/kqoauth/kqoauthutils.h diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 13eb7efc42..58c3f68424 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -332,14 +332,6 @@ list(APPEND libSources thirdparty/kdsingleapplicationguard/kdtoolsglobal.cpp thirdparty/kdsingleapplicationguard/kdlockedsharedmemorypointer.cpp - thirdparty/kqoauth/kqoauth2request.cpp - thirdparty/kqoauth/kqoauthauthreplyserver.cpp - thirdparty/kqoauth/kqoauthmanager.cpp - thirdparty/kqoauth/kqoauthrequest.cpp - thirdparty/kqoauth/kqoauthrequest_1.cpp - thirdparty/kqoauth/kqoauthrequest_xauth.cpp - thirdparty/kqoauth/kqoauthutils.cpp - ) diff --git a/src/libtomahawk/thirdparty/kqoauth/LGPL_EXCEPTION.txt b/src/libtomahawk/thirdparty/kqoauth/LGPL_EXCEPTION.txt deleted file mode 100644 index 8f73eca773..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/LGPL_EXCEPTION.txt +++ /dev/null @@ -1,22 +0,0 @@ -Nokia Qt LGPL Exception version 1.1 - -As an additional permission to the GNU Lesser General Public License version -2.1, the object code form of a "work that uses the Library" may incorporate -material from a header file that is part of the Library. You may distribute -such object code under terms of your choice, provided that: - (i) the header files of the Library have not been modified; and - (ii) the incorporated material is limited to numerical parameters, data - structure layouts, accessors, macros, inline functions and - templates; and - (iii) you comply with the terms of Section 6 of the GNU Lesser General - Public License version 2.1. - -Moreover, you may apply this exception to a modified version of the Library, -provided that such modification does not involve copying material from the -Library into the modified Library's header files unless such material is -limited to (i) numerical parameters; (ii) data structure layouts; -(iii) accessors; and (iv) small macros, templates and inline functions of -five lines or less in length. - -Furthermore, you are not required to apply this additional permission to a -modified version of the Library. diff --git a/src/libtomahawk/thirdparty/kqoauth/LICENSE.LGPL b/src/libtomahawk/thirdparty/kqoauth/LICENSE.LGPL deleted file mode 100644 index 184ea478b2..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/LICENSE.LGPL +++ /dev/null @@ -1,505 +0,0 @@ - - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauth2request.cpp b/src/libtomahawk/thirdparty/kqoauth/kqoauth2request.cpp deleted file mode 100644 index 28ece6973c..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauth2request.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * This file: Kyle Fowler - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see - */ -#include - -#include "kqoauth2request_p.h" -#include "kqoauth2request.h" - -/** - * Private d_ptr implementations. - */ -KQOAuth2Request_Private::KQOAuth2Request_Private() -{ - -} - -KQOAuth2Request_Private::~KQOAuth2Request_Private() -{ -} - -/** - * Public implementations. - */ -KQOAuth2Request::KQOAuth2Request(QObject *parent) : - KQOAuthRequest(parent), - d_ptr(new KQOAuth2Request_Private) -{ -} - -bool KQOAuth2Request::isValid() const { - // Access token must always be retrieved using the POST HTTP method. - // And then check the validity of the XAuth request. - // Provided by the base class as a protected method for us. - return validateOauth2Request(); -} - -void KQOAuth2Request::initRequest(KQOAuthRequest::RequestType type, const QUrl &requestEndpoint) { - KQOAuthRequest::initRequest(type,requestEndpoint); - setRequestOAuthMethod(KQOAuthRequest::OAUTH2); -} diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauth2request.h b/src/libtomahawk/thirdparty/kqoauth/kqoauth2request.h deleted file mode 100644 index 021d159199..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauth2request.h +++ /dev/null @@ -1,50 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * This file: Kyle Fowler - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see . - */ -#ifndef KQOAUTH2REQUEST_H -#define KQOAUTH2REQUEST_H - -#include "kqoauthrequest.h" -#include "kqoauthrequest_1.h" - -class KQOAuth2Request_Private; -class KQOAUTH_EXPORT KQOAuth2Request : public KQOAuthRequest -{ - Q_OBJECT -public: - KQOAuth2Request(QObject *parent = 0); - - /** - * These methods can be overridden in child classes which are different types of - * OAuth requests. - */ - // Validate the request of this type. - bool isValid() const; - void initRequest(KQOAuthRequest::RequestType type, const QUrl &requestEndpoint); - -private: - KQOAuth2Request_Private * const d_ptr; -}; - -#endif // KQOAUTHREQUEST_XAUTH_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauth2request_p.h b/src/libtomahawk/thirdparty/kqoauth/kqoauth2request_p.h deleted file mode 100644 index 2a0dcd3571..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauth2request_p.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef KQOAUTH2REQUEST_P_H -#define KQOAUTH2REQUEST_P_H - -#include "kqoauthglobals.h" - -class KQOAuthRequest; -class KQOAUTH_EXPORT KQOAuth2Request_Private -{ -public: - KQOAuth2Request_Private(); - ~KQOAuth2Request_Private(); -}; - -#endif // KQOAUTHREQUEST_XAUTH_P_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver.cpp b/src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver.cpp deleted file mode 100644 index 30f25de61d..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see - */ -#include -#include -#include -#include -#include -#include - -#include "kqoauthauthreplyserver.h" -#include "kqoauthauthreplyserver_p.h" - -KQOAuthAuthReplyServerPrivate::KQOAuthAuthReplyServerPrivate(KQOAuthAuthReplyServer *parent): - q_ptr(parent) -{ - -} - -KQOAuthAuthReplyServerPrivate::~KQOAuthAuthReplyServerPrivate() -{ - -} - -void KQOAuthAuthReplyServerPrivate::onIncomingConnection() { - Q_Q(KQOAuthAuthReplyServer); - qDebug() << "Incoming Connection"; - socket = q->nextPendingConnection(); - connect(socket, SIGNAL(readyRead()), - this, SLOT(onBytesReady()), Qt::UniqueConnection); -} - -void KQOAuthAuthReplyServerPrivate::onBytesReady() { - Q_Q(KQOAuthAuthReplyServer); - qDebug() << "Socket peer host address: " << socket->peerAddress(); - QByteArray reply; - QByteArray content; - - QByteArray data = socket->readAll(); - qDebug()<< "Query Data: " << data; - QMultiMap queryParams = parseQueryParams(&data); - if(queryParams.size() == 0 && !handlingRedirect) { //assume theres a hash and do the redirect hack - handlingRedirect = true; - content.append("

Account authorized, go ahead back to the tumblr app and start your experience!

"); - } else { - handlingRedirect = false; - QFile file("app/native/assets/" + localFile); - QString fileData; - if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { - qDebug() << "file worked"; - QTextStream in(&file); - while (!in.atEnd()) { - fileData += in.readLine(); - } - file.close(); - } - if(fileData.isEmpty()) { - content.append("

Account linked, go ahead back to the app and check the status!

"); - } else { - content.append(fileData); - } - } - - reply.append("HTTP/1.0 200 OK \r\n"); - reply.append("Content-Type: text/html; charset=\"utf-8\"\r\n"); - reply.append(QString("Content-Length: %1\r\n").arg(content.size())); - reply.append("\r\n"); - reply.append(content); - socket->write(reply); - - if(!handlingRedirect) { - socket->disconnectFromHost(); - q->close(); - emit q->verificationReceived(queryParams); - } -} - -QMultiMap KQOAuthAuthReplyServerPrivate::parseQueryParams(QByteArray *data) { - QString splitGetLine = QString(*data).split("\r\n").first(); // Retrieve the first line with query params. - splitGetLine.remove("GET "); // Clean the line from GET - splitGetLine.remove("HTTP/1.1"); // From HTTP - splitGetLine.remove("\r\n"); // And from rest. - splitGetLine.prepend("http://localhost"); // Now, make it a URL - - QUrl getTokenUrl(splitGetLine); - QList< QPair > tokens = getTokenUrl.queryItems(); // Ask QUrl to do our work. - - QMultiMap queryParams; - QPair tokenPair; - foreach (tokenPair, tokens) { - queryParams.insert(tokenPair.first.trimmed(), tokenPair.second.trimmed()); - } - - return queryParams; -} - - - -KQOAuthAuthReplyServer::KQOAuthAuthReplyServer(QObject *parent) : - QTcpServer(parent), - d_ptr( new KQOAuthAuthReplyServerPrivate(this) ) -{ - Q_D(KQOAuthAuthReplyServer); - - connect(this, SIGNAL(newConnection()), - d, SLOT(onIncomingConnection())); -} - -KQOAuthAuthReplyServer::~KQOAuthAuthReplyServer() -{ - delete d_ptr; -} - - -void KQOAuthAuthReplyServer::setSuccessHtmlFile(QString filePath) { - Q_D(KQOAuthAuthReplyServer); - d->localFile = filePath; -} - - diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver.h deleted file mode 100644 index 82f6d99d24..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver.h +++ /dev/null @@ -1,52 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see - */ -#ifndef KQOAUTHAUTHREPLYSERVER_H -#define KQOAUTHAUTHREPLYSERVER_H - -#include - -#include "kqoauthglobals.h" - -class KQOAuthAuthReplyServerPrivate; -class KQOAUTH_EXPORT KQOAuthAuthReplyServer : public QTcpServer -{ - Q_OBJECT -public: - explicit KQOAuthAuthReplyServer(QObject *parent); - ~KQOAuthAuthReplyServer(); - void setSuccessHtmlFile(QString filePath); - -Q_SIGNALS: - void verificationReceived(QMultiMap); - - -private: - KQOAuthAuthReplyServerPrivate * const d_ptr; - Q_DECLARE_PRIVATE(KQOAuthAuthReplyServer); - Q_DISABLE_COPY(KQOAuthAuthReplyServer); - - -}; - -#endif // KQOAUTHAUTHREPLYSERVER_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver_p.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver_p.h deleted file mode 100644 index 8da4d582e3..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthauthreplyserver_p.h +++ /dev/null @@ -1,53 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see - */ -// Note this class shouldn't be copied or used and the implementation might change later. -#ifndef KQOAUTHAUTHREPLYSERVER_P_H -#define KQOAUTHAUTHREPLYSERVER_P_H - -#include "kqoauthauthreplyserver.h" -#include -#include - -class KQOAUTH_EXPORT KQOAuthAuthReplyServerPrivate: public QObject -{ - Q_OBJECT -public: - KQOAuthAuthReplyServerPrivate( KQOAuthAuthReplyServer * parent ); - ~KQOAuthAuthReplyServerPrivate(); - QMultiMap parseQueryParams(QByteArray *sdata); - -public Q_SLOTS: - void onIncomingConnection(); - void onBytesReady(); - -public: - KQOAuthAuthReplyServer * q_ptr; - Q_DECLARE_PUBLIC(KQOAuthAuthReplyServer); - QTcpSocket *socket; - QString localFile; -private: - bool handlingRedirect; -}; - -#endif // KQOAUTHAUTHREPLYSERVER_P_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthglobals.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthglobals.h deleted file mode 100644 index 203716f764..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthglobals.h +++ /dev/null @@ -1,52 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see - */ -#ifndef KQOAUTHGLOBALS_H -#define KQOAUTHGLOBALS_H - -#include - -#if defined(KQOAUTH) -# define KQOAUTH_EXPORT Q_DECL_EXPORT -#else -# define KQOAUTH_EXPORT Q_DECL_IMPORT -#endif - -//////////// Static constant definitions /////////// -const QString OAUTH_KEY_CONSUMER("oauth_consumer"); -const QString OAUTH_KEY_CONSUMER_KEY("oauth_consumer_key"); -const QString OAUTH_KEY_TOKEN("oauth_token"); -const QString OAUTH_KEY_TOKEN_SECRET("oauth_token_secret"); -const QString OAUTH_KEY_SIGNATURE_METHOD("oauth_signature_method"); -const QString OAUTH_KEY_TIMESTAMP("oauth_timestamp"); -const QString OAUTH_KEY_NONCE("oauth_nonce"); -const QString OAUTH_KEY_SIGNATURE("oauth_signature"); -const QString OAUTH_KEY_CALLBACK("oauth_callback"); -const QString OAUTH_KEY_VERIFIER("oauth_verifier"); -const QString OAUTH_KEY_VERSION("oauth_version"); -const QString OAUTH2_KEY_CLIENT_ID("client_id"); -const QString OAUTH2_KEY_CLIENT_SECRET("client_secret"); -const QString OAUTH2_KEY_REDIRECT_URI("redirect_uri"); -const QString OAUTH2_KEY_RESPONSE_TYPE("response_type"); - -#endif // KQOAUTHGLOBALS_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.cpp b/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.cpp deleted file mode 100644 index 50ae91e211..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.cpp +++ /dev/null @@ -1,729 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see - */ -#include -#include - -#include "kqoauthmanager.h" -#include "kqoauthmanager_p.h" - - -////////////// Private d_ptr implementation //////////////// - -KQOAuthManagerPrivate::KQOAuthManagerPrivate(KQOAuthManager *parent) : - error(KQOAuthManager::NoError) , - r(0) , - opaqueRequest(new KQOAuthRequest) , - q_ptr(parent) , - callbackServer(new KQOAuthAuthReplyServer(parent)) , - isVerified(false) , - isAuthorized(false) , - autoAuth(false), - networkManager(new QNetworkAccessManager), - managerUserSet(false) -{ - -} - -KQOAuthManagerPrivate::~KQOAuthManagerPrivate() { - delete opaqueRequest; - opaqueRequest = 0; - - if (!managerUserSet) { - delete networkManager; - networkManager = 0; - } -} - -QList< QPair > KQOAuthManagerPrivate::createQueryParams(const KQOAuthParameters &requestParams) { - QList requestKeys = requestParams.keys(); - QList requestValues = requestParams.values(); - - QList< QPair > result; - for(int i=0; i KQOAuthManagerPrivate::createTokensFromResponse(QByteArray reply) { - QMultiMap result; - QString replyString(reply); - - QStringList parameterPairs = replyString.split('&', QString::SkipEmptyParts); - foreach (const QString ¶meterPair, parameterPairs) { - QStringList parameter = parameterPair.split('='); - result.insert(parameter.value(0), parameter.value(1)); - } - - return result; -} - -bool KQOAuthManagerPrivate::setSuccessfulRequestToken(const QMultiMap &request) { - if (currentRequestType == KQOAuthRequest::TemporaryCredentials) { - hasTemporaryToken = (!QString(request.value("oauth_token")).isEmpty() && !QString(request.value("oauth_token_secret")).isEmpty()); - } else { - return false; - } - - if (hasTemporaryToken) { - requestToken = QUrl::fromPercentEncoding( QString(request.value("oauth_token")).toLocal8Bit() ); - requestTokenSecret = QUrl::fromPercentEncoding( QString(request.value("oauth_token_secret")).toLocal8Bit() ); - results = request; - } - - return hasTemporaryToken; -} - -bool KQOAuthManagerPrivate::setSuccessfulAuthorized(const QMultiMap &request ) { - if (currentRequestType == KQOAuthRequest::AccessToken) { - isAuthorized = (!QString(request.value("oauth_token")).isEmpty() && !QString(request.value("oauth_token_secret")).isEmpty()); - } else { - return false; - } - - if (isAuthorized) { - requestToken = QUrl::fromPercentEncoding( QString(request.value("oauth_token")).toLocal8Bit() ); - requestTokenSecret = QUrl::fromPercentEncoding( QString(request.value("oauth_token_secret")).toLocal8Bit() ); - results = request; - } - - return isAuthorized; -} - -void KQOAuthManagerPrivate::emitTokens() { - Q_Q(KQOAuthManager); - - if (this->requestToken.isEmpty() || this->requestTokenSecret.isEmpty()) { - error = KQOAuthManager::RequestUnauthorized; - } - - if (currentRequestType == KQOAuthRequest::TemporaryCredentials) { - // Signal that we are ready to use the protected resources. - emit q->temporaryTokenReceived(this->requestToken, this->requestTokenSecret, this->results); - } - - if (currentRequestType == KQOAuthRequest::AccessToken) { - // Signal that we are ready to use the protected resources. - emit q->accessTokenReceived(this->requestToken, this->requestTokenSecret, this->results); - } - - emit q->receivedToken(this->requestToken, this->requestTokenSecret); -} - -bool KQOAuthManagerPrivate::setupCallbackServer() { - return callbackServer->listen(); -} - - -/////////////// Public implementation //////////////// - -KQOAuthManager::KQOAuthManager(QObject *parent) : - QObject(parent) , - d_ptr(new KQOAuthManagerPrivate(this)) -{ - -} - -KQOAuthManager::~KQOAuthManager() -{ - delete d_ptr; -} - -void KQOAuthManager::executeRequest(KQOAuthRequest *request) { - Q_D(KQOAuthManager); - - d->r = request; - - if (request == 0) { - qWarning() << "Request is NULL. Cannot proceed."; - d->error = KQOAuthManager::RequestError; - return; - } - - if (!request->requestEndpoint().isValid()) { - qDebug() << request->requestEndpoint(); - qWarning() << "Request endpoint URL is not valid. Cannot proceed."; - d->error = KQOAuthManager::RequestEndpointError; - return; - } - - if (!request->isValid()) { - qWarning() << "Request is not valid. Cannot proceed."; - d->error = KQOAuthManager::RequestValidationError; - return; - } - - d->currentRequestType = request->requestType(); - - QNetworkRequest networkRequest; - networkRequest.setUrl( request->requestEndpoint() ); - - if (d->autoAuth && d->currentRequestType == KQOAuthRequest::TemporaryCredentials) { - d->setupCallbackServer(); - connect(d->callbackServer, SIGNAL(verificationReceived(QMultiMap)), - this, SLOT( onVerificationReceived(QMultiMap))); - - QString serverString = "http://localhost:"; - serverString.append(QString::number(d->callbackServer->serverPort())); - request->setCallbackUrl(QUrl(serverString)); - qDebug() << serverString; - } - - // And now fill the request with "Authorization" header data. - QList requestHeaders = request->requestParameters(); - QByteArray authHeader; - - bool first = true; - foreach (const QByteArray header, requestHeaders) { - if (!first) { - authHeader.append(", "); - } else { - authHeader.append("OAuth "); - first = false; - } - - authHeader.append(header); - } - networkRequest.setRawHeader("Authorization", authHeader); - - connect(d->networkManager, SIGNAL(finished(QNetworkReply *)), - this, SLOT(onRequestReplyReceived(QNetworkReply *)), Qt::UniqueConnection); - disconnect(d->networkManager, SIGNAL(finished(QNetworkReply *)), - this, SLOT(onAuthorizedRequestReplyReceived(QNetworkReply *))); - - if (request->httpMethod() == KQOAuthRequest::GET) { - // Get the requested additional params as a list of pairs we can give QUrl - QList< QPair > urlParams = d->createQueryParams(request->additionalParameters()); - - // Take the original URL and append the query params to it. - QUrl urlWithParams = networkRequest.url(); - urlWithParams.setQueryItems(urlParams); - networkRequest.setUrl(urlWithParams); - - // Submit the request including the params. - QNetworkReply *reply = d->networkManager->get(networkRequest); - reply->ignoreSslErrors(); - connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), - this, SLOT(slotError(QNetworkReply::NetworkError))); - - } else if (request->httpMethod() == KQOAuthRequest::POST) { - - networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, request->contentType()); - - qDebug() << networkRequest.rawHeaderList(); - qDebug() << networkRequest.rawHeader("Authorization"); - qDebug() << networkRequest.rawHeader("Content-Type"); - - QNetworkReply *reply; - if (request->contentType() == "application/x-www-form-urlencoded") { - reply = d->networkManager->post(networkRequest, request->requestBody()); - } else { - reply = d->networkManager->post(networkRequest, request->rawData()); - } - reply->ignoreSslErrors(); - - connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), - this, SLOT(slotError(QNetworkReply::NetworkError))); - } - - d->r->requestTimerStart(); -} - -void KQOAuthManager::executeAuthorizedRequest(KQOAuthRequest *request, int id) { - Q_D(KQOAuthManager); - - d->r = request; - - if (request == 0) { - qWarning() << "Request is NULL. Cannot proceed."; - d->error = KQOAuthManager::RequestError; - return; - } - - if (!request->requestEndpoint().isValid()) { - qDebug() << request->requestEndpoint(); - qWarning() << "Request endpoint URL is not valid. Cannot proceed."; - d->error = KQOAuthManager::RequestEndpointError; - return; - } - - if (!request->isValid()) { - qWarning() << "Request is not valid. Cannot proceed."; - d->error = KQOAuthManager::RequestValidationError; - return; - } - - d->currentRequestType = request->requestType(); - - QNetworkRequest networkRequest; - networkRequest.setUrl( request->requestEndpoint() ); - - if ( d->currentRequestType != KQOAuthRequest::AuthorizedRequest){ - qWarning() << "Not Authorized Request. Cannot proceed"; - d->error = KQOAuthManager::RequestError; - return; - } - - if(request->oauthMethod() != KQOAuthRequest::OAUTH2) { - // And now fill the request with "Authorization" header data. - QList requestHeaders = request->requestParameters(); - QByteArray authHeader; - - bool first = true; - foreach (const QByteArray header, requestHeaders) { - if (!first) { - authHeader.append(", "); - } else { - authHeader.append("OAuth "); - first = false; - } - - authHeader.append(header); - } - networkRequest.setRawHeader("Authorization", authHeader); - } - - - disconnect(d->networkManager, SIGNAL(finished(QNetworkReply *)), - this, SLOT(onRequestReplyReceived(QNetworkReply *))); - connect(d->networkManager, SIGNAL(finished(QNetworkReply *)), - this, SLOT(onAuthorizedRequestReplyReceived(QNetworkReply*)), Qt::UniqueConnection); - - if (request->httpMethod() == KQOAuthRequest::GET) { - // Get the requested additional params as a list of pairs we can give QUrl - QList< QPair > urlParams = d->createQueryParams(request->additionalParameters()); - - // Take the original URL and append the query params to it. - QUrl urlWithParams = networkRequest.url(); - urlWithParams.setQueryItems(urlParams); - networkRequest.setUrl(urlWithParams); - qDebug() << networkRequest.url(); - - // Submit the request including the params. - QNetworkReply *reply = d->networkManager->get(networkRequest); - reply->ignoreSslErrors(); - connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), - this, SLOT(slotError(QNetworkReply::NetworkError))); - - } else if (request->httpMethod() == KQOAuthRequest::POST) { - - networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, request->contentType()); - - qDebug() << networkRequest.rawHeaderList(); - qDebug() << networkRequest.rawHeader("Authorization"); - qDebug() << networkRequest.rawHeader("Content-Type"); - - QNetworkReply *reply; - if (request->contentType() == "application/x-www-form-urlencoded") { - reply = d->networkManager->post(networkRequest, request->requestBody()); - } else { - reply = d->networkManager->post(networkRequest, request->rawData()); - } - reply->ignoreSslErrors(); - - d->requestIds.insert(reply, id); - - connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), - this, SLOT(slotError(QNetworkReply::NetworkError))); - } - - d->r->requestTimerStart(); -} - - -void KQOAuthManager::setHandleUserAuthorization(bool set) { - Q_D(KQOAuthManager); - - d->autoAuth = set; -} - -bool KQOAuthManager::hasTemporaryToken() { - Q_D(KQOAuthManager); - - return d->hasTemporaryToken; -} - -bool KQOAuthManager::isVerified() { - Q_D(KQOAuthManager); - - return d->isVerified; -} - -bool KQOAuthManager::isAuthorized() { - Q_D(KQOAuthManager); - - return d->isAuthorized; -} - -KQOAuthManager::KQOAuthError KQOAuthManager::lastError() { - Q_D(KQOAuthManager); - - return d->error; -} - -void KQOAuthManager::setNetworkManager(QNetworkAccessManager *manager) { - Q_D(KQOAuthManager); - - if (manager == 0) { - d->error = KQOAuthManager::ManagerError; - return; - } - - if (!d->managerUserSet) { - delete d->networkManager; - } - - d->managerUserSet = true; - d->networkManager = manager; -} - -QNetworkAccessManager * KQOAuthManager::networkManager() const { - Q_D(const KQOAuthManager); - - if (d->managerUserSet) { - return d->networkManager; - } else { - return NULL; - } - -} - -void KQOAuthManager::setSuccessHtmlFile(QString file) { - Q_D(KQOAuthManager); - d->successHtmlFile = file; - d->callbackServer->setSuccessHtmlFile(file); -} - - -//////////// Public convenience API ///////////// -void KQOAuthManager::getOauth2UserAuthorization(QUrl authorizationEndpoint, QString consumerKey, const KQOAuthParameters &additionalParams) { - Q_D(KQOAuthManager); - - d->setupCallbackServer(); - connect(d->callbackServer, SIGNAL(verificationReceived(QMultiMap)), - this, SLOT( onOauth2VerificationReceived(QMultiMap))); - - QString serverString = "http://localhost:"; - serverString.append(QString::number(d->callbackServer->serverPort())); - QUrl openWebPageUrl(authorizationEndpoint.toString(), QUrl::StrictMode); - openWebPageUrl.addQueryItem(OAUTH2_KEY_CLIENT_ID, consumerKey); - openWebPageUrl.addQueryItem(OAUTH2_KEY_RESPONSE_TYPE, "token"); - openWebPageUrl.addQueryItem(OAUTH2_KEY_REDIRECT_URI, serverString); - if(additionalParams.size() > 0) { - QList< QPair > urlParams = d->createQueryParams(additionalParams); - for(int i=0; i < urlParams.length(); i++){ - openWebPageUrl.addQueryItem(urlParams[i].first, urlParams[i].second); - } - } - qDebug() << openWebPageUrl.toString(); - QDesktopServices::openUrl(openWebPageUrl); - //navigator_invoke(openWebPageUrl.toString().toStdString().c_str(),0); -} - -QUrl KQOAuthManager::getUserAuthorizationUrl(QUrl authorizationEndpoint) { - Q_D(KQOAuthManager); - - if (!d->hasTemporaryToken) { - qWarning() << "No temporary tokens retreieved. Cannot get user authorization."; - d->error = KQOAuthManager::RequestUnauthorized; - return QUrl(); - } - - if (!authorizationEndpoint.isValid()) { - qWarning() << "Authorization endpoint not valid. Cannot proceed."; - d->error = KQOAuthManager::RequestEndpointError; - return QUrl(); - } - - d->error = KQOAuthManager::NoError; - - QPair tokenParam = qMakePair(QString("oauth_token"), QString(d->requestToken)); - QUrl openWebPageUrl(authorizationEndpoint.toString(), QUrl::StrictMode); - openWebPageUrl.addQueryItem(tokenParam.first, tokenParam.second); - - qDebug() << openWebPageUrl.toString(); - return openWebPageUrl; -} - -void KQOAuthManager::getUserAuthorization(QUrl authorizationEndpoint) { - QUrl openWebPageUrl = getUserAuthorizationUrl(authorizationEndpoint); - - if(!openWebPageUrl.isEmpty()) { - // Open the user's default browser to the resource authorization page provided - // by the service. - - QDesktopServices::openUrl(openWebPageUrl); - //navigator_invoke(openWebPageUrl.toString().toStdString().c_str(),0); - } -} - -void KQOAuthManager::getUserAccessTokens(QUrl accessTokenEndpoint) { - Q_D(KQOAuthManager); - - if (!d->isVerified) { - qWarning() << "Not verified. Cannot get access tokens."; - d->error = KQOAuthManager::RequestUnauthorized; - return; - } - - if (!accessTokenEndpoint.isValid()) { - qWarning() << "Endpoint for access token exchange is not valid. Cannot proceed."; - d->error = KQOAuthManager::RequestEndpointError; - return; - } - - d->error = KQOAuthManager::NoError; - - d->opaqueRequest->clearRequest(); - d->opaqueRequest->initRequest(KQOAuthRequest::AccessToken, accessTokenEndpoint); - d->opaqueRequest->setToken(d->requestToken); - d->opaqueRequest->setTokenSecret(d->requestTokenSecret); - d->opaqueRequest->setVerifier(d->requestVerifier); - d->opaqueRequest->setConsumerKey(d->consumerKey); - d->opaqueRequest->setConsumerSecretKey(d->consumerKeySecret); - - executeRequest(d->opaqueRequest); -} - -void KQOAuthManager::sendAuthorizedRequest(QUrl requestEndpoint, const KQOAuthParameters &requestParameters) { - Q_D(KQOAuthManager); - - if (!d->isAuthorized) { - qWarning() << "No access tokens retrieved. Cannot send authorized requests."; - d->error = KQOAuthManager::RequestUnauthorized; - return; - } - - if (!requestEndpoint.isValid()) { - qWarning() << "Endpoint for authorized request is not valid. Cannot proceed."; - d->error = KQOAuthManager::RequestEndpointError; - return; - } - - d->error = KQOAuthManager::NoError; - - d->opaqueRequest->clearRequest(); - d->opaqueRequest->initRequest(KQOAuthRequest::AuthorizedRequest, requestEndpoint); - d->opaqueRequest->setAdditionalParameters(requestParameters); - d->opaqueRequest->setToken(d->requestToken); - d->opaqueRequest->setTokenSecret(d->requestTokenSecret); - d->opaqueRequest->setConsumerKey(d->consumerKey); - d->opaqueRequest->setConsumerSecretKey(d->consumerKeySecret); - - executeRequest(d->opaqueRequest); -} - - -/////////////// Private slots ////////////////// - -void KQOAuthManager::onRequestReplyReceived( QNetworkReply *reply ) { - Q_D(KQOAuthManager); - - QNetworkReply::NetworkError networkError = reply->error(); - switch (networkError) { - case QNetworkReply::NoError: - d->error = KQOAuthManager::NoError; - break; - - case QNetworkReply::ContentAccessDenied: - case QNetworkReply::AuthenticationRequiredError: - d->error = KQOAuthManager::RequestUnauthorized; - break; - - default: - d->error = KQOAuthManager::NetworkError; - break; - } - - // Let's disconnect this slot first - /* - disconnect(d->networkManager, SIGNAL(finished(QNetworkReply *)), - this, SLOT(onRequestReplyReceived(QNetworkReply *))); - */ - - // Read the content of the reply from the network. - QByteArray networkReply = reply->readAll(); - - // Stop any timer we have set on the request. - d->r->requestTimerStop(); - - // Just don't do anything if we didn't get anything useful. - if(networkReply.isEmpty()) { - reply->deleteLater(); - return; - } - QMultiMap responseTokens; - - // We need to emit the signal even if we got an error. - if (d->error != KQOAuthManager::NoError) { - reply->deleteLater(); - emit requestReady(networkReply); - d->emitTokens(); - return; - } - - responseTokens = d->createTokensFromResponse(networkReply); - d->opaqueRequest->clearRequest(); - d->opaqueRequest->setHttpMethod(KQOAuthRequest::POST); // XXX FIXME: Convenient API does not support GET - if (!d->isAuthorized || !d->isVerified) { - if (d->setSuccessfulRequestToken(responseTokens)) { - qDebug() << "Successfully got request tokens."; - d->consumerKey = d->r->consumerKeyForManager(); - d->consumerKeySecret = d->r->consumerKeySecretForManager(); - d->opaqueRequest->setSignatureMethod(KQOAuthRequest::HMAC_SHA1); - d->opaqueRequest->setCallbackUrl(d->r->callbackUrlForManager()); - - d->emitTokens(); - - } else if (d->setSuccessfulAuthorized(responseTokens)) { - qDebug() << "Successfully got access tokens."; - d->opaqueRequest->setSignatureMethod(KQOAuthRequest::HMAC_SHA1); - - d->emitTokens(); - } else if (d->currentRequestType == KQOAuthRequest::AuthorizedRequest) { - emit authorizedRequestDone(); - } - } - - emit requestReady(networkReply); - - reply->deleteLater(); // We need to clean this up, after the event processing is done. -} - -void KQOAuthManager::onAuthorizedRequestReplyReceived( QNetworkReply *reply ) { - Q_D(KQOAuthManager); - - QNetworkReply::NetworkError networkError = reply->error(); - switch (networkError) { - case QNetworkReply::NoError: - d->error = KQOAuthManager::NoError; - break; - - case QNetworkReply::ContentAccessDenied: - case QNetworkReply::AuthenticationRequiredError: - d->error = KQOAuthManager::RequestUnauthorized; - break; - - default: - d->error = KQOAuthManager::NetworkError; - break; - } - - /* - disconnect(d->networkManager, SIGNAL(finished(QNetworkReply *)), - this, SLOT(onAuthorizedRequestReplyReceived(QNetworkReply *))); - */ - - // Read the content of the reply from the network. - QByteArray networkReply = reply->readAll(); - - // Stop any timer we have set on the request. - d->r->requestTimerStop(); - - // Just don't do anything if we didn't get anything useful. - if(networkReply.isEmpty()) { - reply->deleteLater(); - return; - } - - // We need to emit the signal even if we got an error. - if (d->error != KQOAuthManager::NoError) { - qWarning() << "Network reply error"; - return; - } - - - d->opaqueRequest->clearRequest(); - d->opaqueRequest->setHttpMethod(KQOAuthRequest::POST); // XXX FIXME: Convenient API does not support GET - if (d->currentRequestType == KQOAuthRequest::AuthorizedRequest) { - emit authorizedRequestDone(); - } - - int id = d->requestIds.take(reply); - emit authorizedRequestReady(networkReply, id); - reply->deleteLater(); -} - - -void KQOAuthManager::onVerificationReceived(QMultiMap response) { - Q_D(KQOAuthManager); - - QString token = response.value("oauth_token"); - QString verifier = response.value("oauth_verifier"); - if (verifier.isEmpty()) { - d->error = KQOAuthManager::RequestUnauthorized; - } - - verifier = QUrl::fromPercentEncoding(verifier.toUtf8()); // We get the raw URL response here so we need to convert it back - // to plain string so we can percent encode it again later in requests. - - if (d->error == KQOAuthManager::NoError) { - d->requestVerifier = verifier; - d->isVerified = true; - } - - emit authorizationReceived(token, verifier); -} - -void KQOAuthManager::onOauth2VerificationReceived(QMultiMap response) { - Q_D(KQOAuthManager); - - foreach(QString key, response.keys()){ - qDebug() << key; - } - - QString token = response.value("access_token"); - if (token.isEmpty()) { - d->error = KQOAuthManager::RequestUnauthorized; - } - - if (d->error == KQOAuthManager::NoError) { - d->isVerified = true; - } - - emit authorizationReceived(token, NULL); -} - -void KQOAuthManager::slotError(QNetworkReply::NetworkError error) { - Q_UNUSED(error) - Q_D(KQOAuthManager); - - d->error = KQOAuthManager::NetworkError; - QByteArray emptyResponse; - emit requestReady(emptyResponse); - emit authorizedRequestDone(); - - QNetworkReply *reply = qobject_cast(sender()); - d->requestIds.remove(reply); - reply->deleteLater(); -} - -void KQOAuthManager::onSslError(QNetworkReply *reply, const QList &errors) { - Q_UNUSED(errors); - reply->ignoreSslErrors(); -} - diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.h deleted file mode 100644 index a99b870f00..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager.h +++ /dev/null @@ -1,205 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see - */ -#ifndef KQOAUTHMANAGER_H -#define KQOAUTHMANAGER_H - -#include -#include -#include - -#include "kqoauthrequest.h" - -class KQOAuthRequest; -class KQOAuthManagerThread; -class KQOAuthManagerPrivate; -class QNetworkAccessManager; -class QUrl; -class QByteArray; -class KQOAUTH_EXPORT KQOAuthManager : public QObject -{ - Q_OBJECT -public: - - enum KQOAuthError { - NoError, // No error - NetworkError, // Network error: timeout, cannot connect. - RequestEndpointError, // Request endpoint is not valid. - RequestValidationError, // Request is not valid: some parameter missing? - RequestUnauthorized, // Authorization error: trying to access a resource without tokens. - RequestError, // The given request to KQOAuthManager is invalid: NULL?, - ManagerError // Manager error, cannot use for sending requests. - }; - - explicit KQOAuthManager(QObject *parent = 0); - ~KQOAuthManager(); - - KQOAuthError lastError(); - - /** - * The manager executes the given request. It takes the HTTP parameters from the - * request and uses QNetworkAccessManager to submit the HTTP request to the net. - * When the request is done it will emit signal requestReady(QByteArray networkReply). - * NOTE: At the moment there is no timeout for the request. - */ - void executeRequest(KQOAuthRequest *request); - void executeAuthorizedRequest(KQOAuthRequest *request, int id); - /** - * Indicates to the user that KQOAuthManager should handle user authorization by - * opening the user's default browser and parsing the reply from the service. - * By setting the parameter to true, KQOAuthManager will store intermediate results - * of the OAuth 1.0 process in its own opaque request. This information is used in - * the user authorization process and also when calling sendAuthorizedRequest(). - * NOTE: You need to set this to true if you want to use getUserAccessTokens() or - * sendAuthorizedRequest(). - */ - void setHandleUserAuthorization(bool set); - - /** - * Returns true if the KQOAuthManager has retrieved the oauth_token value. Otherwise - * return false. - */ - bool hasTemporaryToken(); - /** - * Returns true if the user has authorized us to use the protected resources. Otherwise - * returns false. - * NOTE: In order for KQOAuthManager to know if the user has authorized us to use the - * protected resources, KQOAuthManager must be in control of the user authorization - * process. Hence, this returns true if setHandleUserAuthorization() is set to true - * and the user is authorized with getUserAuthorization(). - */ - bool isVerified(); - /** - * Returns true if KQOAuthManager has the access token and hence can access the protected - * resources. Otherwise returns false. - * NOTE: In order for KQOAuthManager to know if we have access to protected resource - * KQOAuthManager must be in control of the user authorization process and requesting - * the acess token. Hence, this returns true if setHandleUserAuthorization() is set to true - * and the user is authorized with getUserAuthorization() and the access token must be retrieved - * with getUserAccessTokens. - */ - bool isAuthorized(); - - /** - * Sets the file path string that the local server will serve on a successful authentication. This will generally direct - * your user to go back to your application and continue using the app. - */ - void setSuccessHtmlFile(QString filePath); - - /** - * This is a convenience API for authorizing the user. - * The call will verify that a temporary token was received and return the url that the user needs to - * use to authorize the app, it will not open the user's default browser. - */ - QUrl getUserAuthorizationUrl(QUrl authorizationEndpoint); - /** - * This is a convenience API for authorizing the user. - * The call will open the user's default browser, setup a local HTTP server and parse the reply from the - * service after the user has authorized us to access protected resources. If the user authorizes - * us to access protected resources, the verifier token is stored in KQOAuthManager for further use. - * In order to use this method, you must set setHandleUserAuthorization() to true. - */ - void getUserAuthorization(QUrl authorizationEndpoint); - /** - * This is a convenience API for retrieving the access token in exchange for the temporary token and the - * verifier. - * This call will create a KQOAuthRequest and use the previously stored temporary token and verifier to - * exchange for the access token, which will be used to access the protected resources. - * Note that in order to use this method, KQOAuthManager must be in control of the user authorization process. - * Set setHandleUserAuthorization() to true and retrieve user authorization with void getUserAuthorization. - */ - void getUserAccessTokens(QUrl accessTokenEndpoint); - /** - * This is a method for bypassing all the oauth1 auth process and using the browser based oauth2 flow. This will - * launch the browser and set the callback url pointed to a localhost url. Make sure your oauth2 service supports redirect_uri param. - * Add any other params in the additionalParams args like scope or state or any other - */ - void getOauth2UserAuthorization(QUrl authorizationEndpoint, QString consumerKey, const KQOAuthParameters &additionalParams); - /** - * Sends a request to the protected resources. Parameters for the request are service specific and - * are given to the 'requestParameters' as parameters. - * Note that in order to use this method, KQOAuthManager must be in control of the user authorization process. - * Set setHandleUserAuthorization() to true and retrieve user authorization with void getUserAuthorization. - */ - void sendAuthorizedRequest(QUrl requestEndpoint, const KQOAuthParameters &requestParameters); - - /** - * Sets a custom QNetworkAccessManager to handle network requests. This method can be useful if the - * application is using some proxy settings for example. - * The application is responsible for deleting this manager. KQOAuthManager will not delete any - * previously given manager. - * If the manager is NULL, the manager will not be set and the KQOAuthManager::Error. - * If no manager is given, KQOAuthManager will use the default one it will create by itself. - */ - void setNetworkManager(QNetworkAccessManager *manager); - - /** - * Returns the given QNetworkAccessManager. Returns NULL if none is given. - */ - QNetworkAccessManager* networkManager() const; - -Q_SIGNALS: - // This signal will be emitted after each request has got a reply. - // Parameter is the raw response from the service. - void requestReady(QByteArray networkReply); - - void authorizedRequestReady(QByteArray networkReply, int id); - - // This signal will be emited when we have an request tokens available - // (either temporary resource tokens, or authorization tokens). - void receivedToken(QString oauth_token, QString oauth_token_secret); // oauth_token, oauth_token_secret - - // This signal is emited when temporary tokens are returned from the service. - // Note that this signal is also emited in case temporary tokens are not available. - void temporaryTokenReceived(QString oauth_token, QString oauth_token_secret, QMultiMap results); // oauth_token, oauth_token_secret - - // This signal is emited when the user has authenticated the application to - // communicate with the protected resources. Next we need to exchange the - // temporary tokens for access tokens. - // Note that this signal is also emited if user denies access. - void authorizationReceived(QString oauth_token, QString oauth_verifier); // oauth_token, oauth_verifier - - // This signal is emited when access tokens are received from the service. We are - // ready to start communicating with the protected resources. - void accessTokenReceived(QString oauth_token, QString oauth_token_secret, QMultiMap results); // oauth_token, oauth_token_secret - - // This signal is emited when the authorized request is done. - // This ends the kQOAuth interactions. - void authorizedRequestDone(); - -private Q_SLOTS: - void onRequestReplyReceived( QNetworkReply *reply ); - void onAuthorizedRequestReplyReceived( QNetworkReply *reply ); - void onVerificationReceived(QMultiMap response); - void onOauth2VerificationReceived(QMultiMap response); - void slotError(QNetworkReply::NetworkError error); - void onSslError(QNetworkReply *reply, const QList &errors); - -private: - KQOAuthManagerPrivate *d_ptr; - Q_DECLARE_PRIVATE(KQOAuthManager); - Q_DISABLE_COPY(KQOAuthManager); - -}; - -#endif // KQOAUTHMANAGER_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager_p.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager_p.h deleted file mode 100644 index cd2c0a1e05..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthmanager_p.h +++ /dev/null @@ -1,80 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see - */ -#ifndef KQOAUTHMANAGER_P_H -#define KQOAUTHMANAGER_P_H - -#include "kqoauthauthreplyserver.h" -#include "kqoauthrequest.h" - -class KQOAUTH_EXPORT KQOAuthManagerPrivate { - -public: - KQOAuthManagerPrivate(KQOAuthManager *parent); - ~KQOAuthManagerPrivate(); - - QList< QPair > createQueryParams(const KQOAuthParameters &requestParams); - QMultiMap createTokensFromResponse(QByteArray reply); - bool setSuccessfulRequestToken(const QMultiMap &request); - bool setSuccessfulAuthorized(const QMultiMap &request); - void emitTokens(); - bool setupCallbackServer(); - - KQOAuthManager::KQOAuthError error; - KQOAuthRequest *r; // This request is used to cache the user sent request. - KQOAuthRequest *opaqueRequest; // This request is used to creating opaque convenience requests for the user. - KQOAuthManager * const q_ptr; - - /** - * The items below are needed in order to store the state of the manager and - * by that be able to do convenience operations for the user. - */ - KQOAuthRequest::RequestType currentRequestType; - - // Variables we store here for opaque request handling. - // NOTE: The variables are labeled the same for both access token request - // and protected resource access. - QString requestToken; - QString requestTokenSecret; - QString consumerKey; - QString consumerKeySecret; - QString requestVerifier; - QMultiMap results; - - - QString successHtmlFile; - - KQOAuthAuthReplyServer *callbackServer; - - bool hasTemporaryToken; - bool isVerified; - bool isAuthorized; - bool autoAuth; - QNetworkAccessManager *networkManager; - bool managerUserSet; - QMap requestIds; - - Q_DECLARE_PUBLIC(KQOAuthManager); -}; - -#endif // KQOAUTHMANAGER_P_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest.cpp b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest.cpp deleted file mode 100644 index e81b56dfee..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest.cpp +++ /dev/null @@ -1,625 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see - */ -#include -#include -#include -#include -#include - -#include -#include - -#include "kqoauthrequest.h" -#include "kqoauthrequest_p.h" -#include "kqoauthutils.h" -#include "kqoauthglobals.h" - - -//////////// Private d_ptr implementation ///////// - -KQOAuthRequestPrivate::KQOAuthRequestPrivate() : - timeout(0) -{ - -} - -KQOAuthRequestPrivate::~KQOAuthRequestPrivate() -{ - -} - -// This method will not include the "oauthSignature" paramater, since it is calculated from these parameters. -void KQOAuthRequestPrivate::prepareRequest() { - - // If parameter list is not empty, we don't want to insert these values by - // accident a second time. So giving up. - if( !requestParameters.isEmpty() ) { - return; - } - - switch ( requestType ) { - case KQOAuthRequest::TemporaryCredentials: - requestParameters.append( qMakePair( OAUTH_KEY_CALLBACK, oauthCallbackUrl.toString()) ); // This is so ugly that it is almost beautiful. - requestParameters.append( qMakePair( OAUTH_KEY_SIGNATURE_METHOD, oauthSignatureMethod) ); - requestParameters.append( qMakePair( OAUTH_KEY_CONSUMER_KEY, oauthConsumerKey )); - requestParameters.append( qMakePair( OAUTH_KEY_VERSION, oauthVersion )); - requestParameters.append( qMakePair( OAUTH_KEY_TIMESTAMP, this->oauthTimestamp() )); - requestParameters.append( qMakePair( OAUTH_KEY_NONCE, this->oauthNonce() )); - break; - - case KQOAuthRequest::AccessToken: - requestParameters.append( qMakePair( OAUTH_KEY_SIGNATURE_METHOD, oauthSignatureMethod )); - requestParameters.append( qMakePair( OAUTH_KEY_CONSUMER_KEY, oauthConsumerKey )); - requestParameters.append( qMakePair( OAUTH_KEY_VERSION, oauthVersion )); - requestParameters.append( qMakePair( OAUTH_KEY_TIMESTAMP, this->oauthTimestamp() )); - requestParameters.append( qMakePair( OAUTH_KEY_NONCE, this->oauthNonce() )); - requestParameters.append( qMakePair( OAUTH_KEY_VERIFIER, oauthVerifier )); - requestParameters.append( qMakePair( OAUTH_KEY_TOKEN, oauthToken )); - break; - - case KQOAuthRequest::AuthorizedRequest: - requestParameters.append( qMakePair( OAUTH_KEY_SIGNATURE_METHOD, oauthSignatureMethod )); - requestParameters.append( qMakePair( OAUTH_KEY_CONSUMER_KEY, oauthConsumerKey )); - requestParameters.append( qMakePair( OAUTH_KEY_VERSION, oauthVersion )); - requestParameters.append( qMakePair( OAUTH_KEY_TIMESTAMP, this->oauthTimestamp() )); - requestParameters.append( qMakePair( OAUTH_KEY_NONCE, this->oauthNonce() )); - requestParameters.append( qMakePair( OAUTH_KEY_TOKEN, oauthToken )); - break; - - default: - break; - } -} - -void KQOAuthRequestPrivate::signRequest() { - QString signature = this->oauthSignature(); - requestParameters.append( qMakePair( OAUTH_KEY_SIGNATURE, signature) ); -} - -QString KQOAuthRequestPrivate::oauthSignature() { - /** - * http://oauth.net/core/1.0/#anchor16 - * The HMAC-SHA1 signature method uses the HMAC-SHA1 signature algorithm as defined in [RFC2104] where the - * Signature Base String is the text and the key is the concatenated values (each first encoded per Parameter - * Encoding) of the Consumer Secret and Token Secret, separated by an ‘&’ character (ASCII code 38) even if empty. - **/ - QByteArray baseString = this->requestBaseString(); - - QString secret = QString(QUrl::toPercentEncoding(oauthConsumerSecretKey)) + "&" + QString(QUrl::toPercentEncoding(oauthTokenSecret)); - QString signature = KQOAuthUtils::hmac_sha1(baseString, secret); - - if (debugOutput) { - qDebug() << "========== KQOAuthRequest has the following signature:"; - qDebug() << " * Signature : " << QUrl::toPercentEncoding(signature) << "\n"; - } - return QString( QUrl::toPercentEncoding(signature) ); -} - -bool normalizedParameterSort(const QPair &left, const QPair &right) { - QString keyLeft = left.first; - QString valueLeft = left.second; - QString keyRight = right.first; - QString valueRight = right.second; - - if(keyLeft == keyRight) { - return (valueLeft < valueRight); - } else { - return (keyLeft < keyRight); - } -} -QByteArray KQOAuthRequestPrivate::requestBaseString() { - QByteArray baseString; - - // Every request has these as the commont parameters. - baseString.append( oauthHttpMethodString.toUtf8() + "&"); // HTTP method - baseString.append( QUrl::toPercentEncoding( oauthRequestEndpoint.toString(QUrl::RemoveQuery) ) + "&" ); // The path and query components - - QList< QPair > baseStringParameters; - baseStringParameters.append(requestParameters); - baseStringParameters.append(additionalParameters); - - // Sort the request parameters. These parameters have been - // initialized earlier. - qSort(baseStringParameters.begin(), - baseStringParameters.end(), - normalizedParameterSort - ); - - // Last append the request parameters correctly encoded. - baseString.append( encodedParamaterList(baseStringParameters) ); - - if (debugOutput) { - qDebug() << "========== KQOAuthRequest has the following base string:"; - qDebug() << baseString << "\n"; - } - - return baseString; -} - -QByteArray KQOAuthRequestPrivate::encodedParamaterList(const QList< QPair > ¶meters) { - QByteArray resultList; - - bool first = true; - QPair parameter; - - // Do the debug output. - if (debugOutput) { - qDebug() << "========== KQOAuthRequest has the following parameters:"; - } - foreach (parameter, parameters) { - if(!first) { - resultList.append( "&" ); - } else { - first = false; - } - - // Here we don't need to explicitely encode the strings to UTF-8 since - // QUrl::toPercentEncoding() takes care of that for us. - resultList.append( QUrl::toPercentEncoding(parameter.first) // Parameter key - + "=" - + QUrl::toPercentEncoding(parameter.second) // Parameter value - ); - if (debugOutput) { - qDebug() << " * " - << parameter.first - << " : " - << parameter.second; - } - } - if (debugOutput) { - qDebug() << "\n"; - } - - return QUrl::toPercentEncoding(resultList); -} - -QString KQOAuthRequestPrivate::oauthTimestamp() const { - // This is basically for unit tests only. In most cases we don't set the nonce beforehand. - if (!oauthTimestamp_.isEmpty()) { - return oauthTimestamp_; - } - -#if QT_VERSION >= 0x040700 - return QString::number(QDateTime::currentDateTimeUtc().toTime_t()); -#else - return QString::number(QDateTime::currentDateTime().toUTC().toTime_t()); -#endif - -} - -QString KQOAuthRequestPrivate::oauthNonce() const { - // This is basically for unit tests only. In most cases we don't set the nonce beforehand. - return QString::number(qrand()); -} - -bool KQOAuthRequestPrivate::validateRequest() const { - switch ( requestType ) { - case KQOAuthRequest::TemporaryCredentials: - if (oauthRequestEndpoint.isEmpty() - || oauthConsumerKey.isEmpty() - || oauthNonce_.isEmpty() - || oauthSignatureMethod.isEmpty() - || oauthTimestamp_.isEmpty() - || oauthVersion.isEmpty()) - { - return false; - } - return true; - - case KQOAuthRequest::AccessToken: - if (oauthRequestEndpoint.isEmpty() - || oauthVerifier.isEmpty() - || oauthConsumerKey.isEmpty() - || oauthNonce_.isEmpty() - || oauthSignatureMethod.isEmpty() - || oauthTimestamp_.isEmpty() - || oauthToken.isEmpty() - || oauthTokenSecret.isEmpty() - || oauthVersion.isEmpty()) - { - return false; - } - return true; - - case KQOAuthRequest::AuthorizedRequest: - if(requestOAuthMethod == KQOAuthRequest::OAUTH1) { - if (oauthRequestEndpoint.isEmpty() - || oauthConsumerKey.isEmpty() - || oauthNonce_.isEmpty() - || oauthSignatureMethod.isEmpty() - || oauthTimestamp_.isEmpty() - || oauthToken.isEmpty() - || oauthTokenSecret.isEmpty() - || oauthVersion.isEmpty()) - { - return false; - } - return true; - } else { - if(oauthToken.isEmpty()){ - return false; - } - return true; - } - - default: - return false; - } - - // We should not come here. - return false; -} - -//////////// Public implementation //////////////// - -KQOAuthRequest::KQOAuthRequest(QObject *parent) : - QObject(parent), - d_ptr(new KQOAuthRequestPrivate) -{ - d_ptr->debugOutput = false; // No debug output by default. - qsrand(QTime::currentTime().msec()); // We need to seed the nonce random number with something. - // However, we cannot do this while generating the nonce since - // we might get the same seed. So initializing here should be fine. -} - -KQOAuthRequest::~KQOAuthRequest() -{ - delete d_ptr; -} - -void KQOAuthRequest::initRequest(KQOAuthRequest::RequestType type, const QUrl &requestEndpoint) { - Q_D(KQOAuthRequest); - - if (!requestEndpoint.isValid()) { - qWarning() << "Endpoint URL is not valid. Ignoring. This request might not work."; - return; - } - - if (type < 0 || type > KQOAuthRequest::AuthorizedRequest) { - qWarning() << "Invalid request type. Ignoring. This request might not work."; - return; - } - - // Clear the request - clearRequest(); - - // Set smart defaults. - d->requestType = type; - d->oauthRequestEndpoint = requestEndpoint; - d->oauthTimestamp_ = d->oauthTimestamp(); - d->oauthNonce_ = d->oauthNonce(); - this->setSignatureMethod(KQOAuthRequest::HMAC_SHA1); - this->setHttpMethod(KQOAuthRequest::POST); - this->setRequestOAuthMethod(KQOAuthRequest::OAUTH1); - d->oauthVersion = "1.0"; // Currently supports only version 1.0 - - d->contentType = "application/x-www-form-urlencoded"; -} - -void KQOAuthRequest::setConsumerKey(const QString &consumerKey) { - Q_D(KQOAuthRequest); - d->oauthConsumerKey = consumerKey; -} - -void KQOAuthRequest::setConsumerSecretKey(const QString &consumerSecretKey) { - Q_D(KQOAuthRequest); - d->oauthConsumerSecretKey = consumerSecretKey; -} - -void KQOAuthRequest::setCallbackUrl(const QUrl &callbackUrl) { - Q_D(KQOAuthRequest); - - d->oauthCallbackUrl = callbackUrl; -} - -void KQOAuthRequest::setSignatureMethod(KQOAuthRequest::RequestSignatureMethod requestMethod) { - Q_D(KQOAuthRequest); - QString requestMethodString; - - switch (requestMethod) { - case KQOAuthRequest::PLAINTEXT: - requestMethodString = "PLAINTEXT"; - break; - case KQOAuthRequest::HMAC_SHA1: - requestMethodString = "HMAC-SHA1"; - break; - case KQOAuthRequest::RSA_SHA1: - requestMethodString = "RSA-SHA1"; - break; - default: - // We should not come here - qWarning() << "Invalid signature method set."; - break; - } - - d->oauthSignatureMethod = requestMethodString; -} - -void KQOAuthRequest::setTokenSecret(const QString &tokenSecret) { - Q_D(KQOAuthRequest); - - d->oauthTokenSecret = tokenSecret; -} - -void KQOAuthRequest::setToken(const QString &token) { - Q_D(KQOAuthRequest); - - d->oauthToken = token; -} - -void KQOAuthRequest::setVerifier(const QString &verifier) { - Q_D(KQOAuthRequest); - - d->oauthVerifier = verifier; -} - - -void KQOAuthRequest::setHttpMethod(KQOAuthRequest::RequestHttpMethod httpMethod) { - Q_D(KQOAuthRequest); - - QString requestHttpMethodString; - - switch (httpMethod) { - case KQOAuthRequest::GET: - requestHttpMethodString = "GET"; - break; - case KQOAuthRequest::POST: - requestHttpMethodString = "POST"; - break; - default: - qWarning() << "Invalid HTTP method set."; - break; - } - - d->oauthHttpMethod = httpMethod; - d->oauthHttpMethodString = requestHttpMethodString; -} - -void KQOAuthRequest::setRequestOAuthMethod(KQOAuthRequest::RequestOAuthMethod oauthMethod) { - Q_D(KQOAuthRequest); - - d->requestOAuthMethod = oauthMethod; -} - -KQOAuthRequest::RequestHttpMethod KQOAuthRequest::httpMethod() const { - Q_D(const KQOAuthRequest); - - return d->oauthHttpMethod; -} - -KQOAuthRequest::RequestOAuthMethod KQOAuthRequest::oauthMethod() const { - Q_D(const KQOAuthRequest); - - return d->requestOAuthMethod; -} - -void KQOAuthRequest::setAdditionalParameters(const KQOAuthParameters &additionalParams) { - Q_D(KQOAuthRequest); - - QList additionalKeys = additionalParams.keys(); - QList additionalValues = additionalParams.values(); - - int i=0; - foreach(QString key, additionalKeys) { - QString value = additionalValues.at(i); - d->additionalParameters.append( qMakePair(key, value) ); - i++; - } -} - -KQOAuthParameters KQOAuthRequest::additionalParameters() const { - Q_D(const KQOAuthRequest); - - QMultiMap additionalParams; - for(int i=0; iadditionalParameters.size(); i++) { - additionalParams.insert(d->additionalParameters.at(i).first, - d->additionalParameters.at(i).second); - } - if(d->requestOAuthMethod == KQOAuthRequest::OAUTH2) { - additionalParams.insert(OAUTH_KEY_TOKEN, d->oauthToken); - } - - return additionalParams; -} - -KQOAuthRequest::RequestType KQOAuthRequest::requestType() const { - Q_D(const KQOAuthRequest); - return d->requestType; -} - -QUrl KQOAuthRequest::requestEndpoint() const { - Q_D(const KQOAuthRequest); - return d->oauthRequestEndpoint; -} - -QList KQOAuthRequest::requestParameters() { - Q_D(KQOAuthRequest); - - QList requestParamList; - - d->prepareRequest(); - if (!isValid() ) { - qWarning() << "Request is not valid! I will still sign it, but it will probably not work."; - } - if(d->requestOAuthMethod != KQOAuthRequest::OAUTH2) { - d->signRequest(); - } - - QPair requestParam; - QString param; - QString value; - foreach (requestParam, d->requestParameters) { - param = requestParam.first; - value = requestParam.second; - requestParamList.append(QString(param + "=\"" + value +"\"").toUtf8()); - } - - return requestParamList; -} - -QString KQOAuthRequest::contentType() -{ - Q_D(const KQOAuthRequest); - return d->contentType; -} - -void KQOAuthRequest::setContentType(const QString &contentType) -{ - Q_D(KQOAuthRequest); - d->contentType = contentType; -} - -QByteArray KQOAuthRequest::rawData() -{ - Q_D(const KQOAuthRequest); - return d->postRawData; -} - -void KQOAuthRequest::setRawData(const QByteArray &rawData) -{ - Q_D(KQOAuthRequest); - d->postRawData = rawData; -} - -QByteArray KQOAuthRequest::requestBody() const { - Q_D(const KQOAuthRequest); - - QByteArray postBodyContent; - bool first = true; - for(int i=0; i < d->additionalParameters.size(); i++) { - if(!first) { - postBodyContent.append("&"); - } else { - first = false; - } - - QString key = d->additionalParameters.at(i).first; - QString value = d->additionalParameters.at(i).second; - - postBodyContent.append(QUrl::toPercentEncoding(key) + QString("=").toUtf8() + - QUrl::toPercentEncoding(value)); - } - qDebug() << postBodyContent; - return postBodyContent; -} - -bool KQOAuthRequest::isValid() const { - Q_D(const KQOAuthRequest); - - return d->validateRequest(); -} - -void KQOAuthRequest::setTimeout(int timeoutMilliseconds) { - Q_D(KQOAuthRequest); - d->timeout = timeoutMilliseconds; -} - -void KQOAuthRequest::clearRequest() { - Q_D(KQOAuthRequest); - - d->oauthRequestEndpoint = ""; - d->oauthHttpMethodString = ""; - d->oauthConsumerKey = ""; - d->oauthConsumerSecretKey = ""; - d->oauthToken = ""; - d->oauthTokenSecret = ""; - d->oauthSignatureMethod = ""; - d->oauthCallbackUrl = ""; - d->oauthVerifier = ""; - d->oauthTimestamp_ = ""; - d->oauthNonce_ = ""; - d->requestParameters.clear(); - d->additionalParameters.clear(); - d->timeout = 0; -} - -void KQOAuthRequest::setEnableDebugOutput(bool enabled) { - Q_D(KQOAuthRequest); - d->debugOutput = enabled; -} - -/** - * Protected implementations for inherited classes - */ -bool KQOAuthRequest::validateXAuthRequest() const { - Q_D(const KQOAuthRequest); - - if (d->oauthRequestEndpoint.isEmpty() - || d->oauthConsumerKey.isEmpty() - || d->oauthNonce_.isEmpty() - || d->oauthSignatureMethod.isEmpty() - || d->oauthTimestamp_.isEmpty() - || d->oauthVersion.isEmpty()) - { - return false; - } - return true; -} - -bool KQOAuthRequest::validateOauth2Request() const { - Q_D(const KQOAuthRequest); - - if (d->oauthRequestEndpoint.isEmpty() || d->oauthToken.isEmpty()) - { - return false; - } - return true; -} - - -/** - * Private implementations for friend classes - */ -QString KQOAuthRequest::consumerKeyForManager() const { - Q_D(const KQOAuthRequest); - return d->oauthConsumerKey; -} - -QString KQOAuthRequest::consumerKeySecretForManager() const { - Q_D(const KQOAuthRequest); - return d->oauthConsumerSecretKey; -} - -QUrl KQOAuthRequest::callbackUrlForManager() const { - Q_D(const KQOAuthRequest); - return d->oauthCallbackUrl; -} - -void KQOAuthRequest::requestTimerStart() -{ - Q_D(KQOAuthRequest); - if (d->timeout > 0) { - connect(&(d->timer), SIGNAL(timeout()), this, SIGNAL(requestTimedout())); - d->timer.start(d->timeout); - } -} - -void KQOAuthRequest::requestTimerStop() -{ - Q_D(KQOAuthRequest); - if (d->timeout > 0) { - disconnect(&(d->timer), SIGNAL(timeout()), this, SIGNAL(requestTimedout())); - d->timer.stop(); - } -} diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest.h deleted file mode 100644 index 616003db73..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest.h +++ /dev/null @@ -1,157 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see - */ -#ifndef KQOAUTHREQUEST_H -#define KQOAUTHREQUEST_H - -#include -#include -#include - -#include "kqoauthglobals.h" - -typedef QMultiMap KQOAuthParameters; - -class KQOAuthRequestPrivate; -class KQOAUTH_EXPORT KQOAuthRequest : public QObject -{ - Q_OBJECT -public: - explicit KQOAuthRequest(QObject *parent = 0); - ~KQOAuthRequest(); - - enum RequestType { - TemporaryCredentials = 0, - AccessToken, - AuthorizedRequest - }; - - enum RequestSignatureMethod { - PLAINTEXT = 0, - HMAC_SHA1, - RSA_SHA1 - }; - - enum RequestHttpMethod { - GET = 0, - POST - }; - - enum RequestOAuthMethod { - OAUTH1 = 0, - OAUTH2 - }; - - /** - * These methods can be overridden in child classes which are different types of - * OAuth requests. - */ - // Validate the request of this type. - virtual bool isValid() const; - - /** - * These methods are OAuth request type specific and not overridden in child - * classes. - * NOTE: Refactorting still a TODO - */ - // Initialize the request of this type. - virtual void initRequest(KQOAuthRequest::RequestType type, const QUrl &requestEndpoint); - - void setConsumerKey(const QString &consumerKey); - void setConsumerSecretKey(const QString &consumerSecretKey); - - // Mandatory methods for acquiring a request token - void setCallbackUrl(const QUrl &callbackUrl); - - // Mandator methods for acquiring a access token - void setTokenSecret(const QString &tokenSecret); - void setToken(const QString &token); - void setVerifier(const QString &verifier); - - // Request signature method to use - HMAC_SHA1 currently only supported - void setSignatureMethod(KQOAuthRequest::RequestSignatureMethod = KQOAuthRequest::HMAC_SHA1); - - // Request's HTTP method. - void setHttpMethod(KQOAuthRequest::RequestHttpMethod = KQOAuthRequest::POST); - KQOAuthRequest::RequestHttpMethod httpMethod() const; - KQOAuthRequest::RequestOAuthMethod oauthMethod() const; - void setRequestOAuthMethod(KQOAuthRequest::RequestOAuthMethod = KQOAuthRequest::OAUTH1); - - // Sets the timeout for this request. If the timeout expires, signal "requestTimedout" will be - // emitted from the manager. - // 0 = If set to zero, timeout is disabled. - // TODO: Do we need some request ID now? - void setTimeout(int timeoutMilliseconds); - - // Additional optional parameters to the request. - void setAdditionalParameters(const KQOAuthParameters &additionalParams); - KQOAuthParameters additionalParameters() const; - QList requestParameters(); // This will return all request's parameters in the raw format given - // to the QNetworkRequest. - QByteArray requestBody() const; // This will return the POST body as given to the QNetworkRequest. - - KQOAuthRequest::RequestType requestType() const; - QUrl requestEndpoint() const; - - void setContentType(const QString &contentType); - QString contentType(); - - void setRawData(const QByteArray &rawData); - QByteArray rawData(); - - void clearRequest(); - - // Enable verbose debug output for request content. - void setEnableDebugOutput(bool enabled); - -Q_SIGNALS: - // This signal is emited if the request is not completed before the request's timeout - // value has expired. - void requestTimedout(); - -protected: - bool validateXAuthRequest() const; - bool validateOauth2Request() const; - -private: - KQOAuthRequestPrivate * const d_ptr; - Q_DECLARE_PRIVATE(KQOAuthRequest); - Q_DISABLE_COPY(KQOAuthRequest); - - // These classes are only for the internal use of KQOAuthManager so it can - // work with the opaque request. - QString consumerKeyForManager() const; - QString consumerKeySecretForManager() const; - QUrl callbackUrlForManager() const; - - // This method is for timeout handling by the KQOAuthManager. - void requestTimerStart(); - void requestTimerStop(); - - friend class KQOAuthManager; -#ifdef UNIT_TEST - friend class Ut_KQOAuth; -#endif -}; - -#endif // KQOAUTHREQUEST_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_1.cpp b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_1.cpp deleted file mode 100644 index 165eb3c23d..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_1.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "kqoauthrequest_1.h" - -KQOAuthRequest_1::KQOAuthRequest_1() -{ -} diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_1.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_1.h deleted file mode 100644 index 8da5df8f4b..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_1.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef KQOAUTHREQUEST_1_H -#define KQOAUTHREQUEST_1_H - -#include "kqoauthrequest.h" - -class KQOAUTH_EXPORT KQOAuthRequest_1 : public KQOAuthRequest -{ -public: - KQOAuthRequest_1(); -}; - -#endif // KQOAUTHREQUEST_1_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_p.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_p.h deleted file mode 100644 index 22be4ef7eb..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_p.h +++ /dev/null @@ -1,98 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see - */ -#ifndef KQOAUTHREQUEST_P_H -#define KQOAUTHREQUEST_P_H -#include "kqoauthglobals.h" -#include "kqoauthrequest.h" - -#include -#include -#include -#include -#include -#include - -class KQOAUTH_EXPORT KQOAuthRequestPrivate { - -public: - KQOAuthRequestPrivate(); - ~KQOAuthRequestPrivate(); - - // Helper methods to get the values for the OAuth request parameters. - QString oauthTimestamp() const; - QString oauthNonce() const; - QString oauthSignature(); - - // Utility methods for making the request happen. - void prepareRequest(); - void signRequest(); - bool validateRequest() const; - QByteArray requestBaseString(); - QByteArray encodedParamaterList(const QList< QPair > &requestParameters); - void insertAdditionalParams(); - void insertPostBody(); - - QUrl oauthRequestEndpoint; - KQOAuthRequest::RequestHttpMethod oauthHttpMethod; - QString oauthHttpMethodString; - QString oauthConsumerKey; - QString oauthConsumerSecretKey; - QString oauthToken; - QString oauthTokenSecret; - QString oauthSignatureMethod; - QUrl oauthCallbackUrl; - QString oauthVersion; - QString oauthVerifier; - - // These will be generated by the helper methods - QString oauthTimestamp_; - QString oauthNonce_; - - // User specified additional parameters needed for the request. - QList< QPair > additionalParameters; - - // The raw POST body content as given to the HTTP request. - QByteArray postBodyContent; - - // Protocol parameters. - // These parameters are used in the "Authorized" header of the HTTP request. - QList< QPair > requestParameters; - - KQOAuthRequest::RequestType requestType; - KQOAuthRequest::RequestOAuthMethod requestOAuthMethod; - - //The Content-Type HTTP header - QString contentType; - - //Raw data to post if type is not url-encoded - QByteArray postRawData; - - // Timeout for this request in milliseconds. - int timeout; - QTimer timer; - - bool debugOutput; - -}; -#endif // KQOAUTHREQUEST_P_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth.cpp b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth.cpp deleted file mode 100644 index 9f6a8593da..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see - */ -#include - -#include "kqoauthrequest_xauth_p.h" -#include "kqoauthrequest_xauth.h" - -/** - * Private d_ptr implementations. - */ -KQOAuthRequest_XAuthPrivate::KQOAuthRequest_XAuthPrivate() -{ - -} - -KQOAuthRequest_XAuthPrivate::~KQOAuthRequest_XAuthPrivate() -{ -} - -/** - * Public implementations. - */ -KQOAuthRequest_XAuth::KQOAuthRequest_XAuth(QObject *parent) : - KQOAuthRequest(parent), - d_ptr(new KQOAuthRequest_XAuthPrivate) -{ -} - -bool KQOAuthRequest_XAuth::isValid() const { - // An xAuth can never request temporary credentials. - if (requestType() == KQOAuthRequest::TemporaryCredentials) { - qWarning() << "XAuth request cannot be of type KQOAuthRequest::TemporaryCredentials. Aborting."; - return false; - } - - // Access token must always be retrieved using the POST HTTP method. - if (requestType() == KQOAuthRequest::AccessToken - && httpMethod() != KQOAuthRequest::POST) { - - qWarning() << "Access tokens must be fetched using the POST HTTP method. Aborting."; - - return false; - } - - if (!xauth_parameters_set) { - qWarning() << "No XAuth parameters set. Aborting."; - return false; - } - - // And then check the validity of the XAuth request. - // Provided by the base class as a protected method for us. - return validateXAuthRequest(); -} - -void KQOAuthRequest_XAuth::setXAuthLogin(const QString &username, - const QString &password) { - - if (username.isEmpty() || password.isEmpty()) { - qWarning() << "Username or password cannot be empty. Aborting."; - return; - } - - xauth_parameters_set = true; - - qDebug() << username << password; - - KQOAuthParameters xauthParams; - xauthParams.insert("x_auth_username", username); - xauthParams.insert("x_auth_password", password); - xauthParams.insert("x_auth_mode", "client_auth"); - - setAdditionalParameters(xauthParams); -} - diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth.h deleted file mode 100644 index 93539cb785..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth.h +++ /dev/null @@ -1,53 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see - */ -#ifndef KQOAUTHREQUEST_XAUTH_H -#define KQOAUTHREQUEST_XAUTH_H - -#include "kqoauthrequest.h" -#include "kqoauthrequest_1.h" - -class KQOAuthRequest_XAuthPrivate; -class KQOAUTH_EXPORT KQOAuthRequest_XAuth : public KQOAuthRequest -{ - Q_OBJECT -public: - KQOAuthRequest_XAuth(QObject *parent = 0); - - /** - * These methods can be overridden in child classes which are different types of - * OAuth requests. - */ - // Validate the request of this type. - bool isValid() const; - - // Give the xAuth specific parameters. - void setXAuthLogin(const QString &username = "", - const QString &password = ""); - -private: - KQOAuthRequest_XAuthPrivate * const d_ptr; - bool xauth_parameters_set; -}; - -#endif // KQOAUTHREQUEST_XAUTH_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth_p.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth_p.h deleted file mode 100644 index 9f79d31ef8..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthrequest_xauth_p.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef KQOAUTHREQUEST_XAUTH_P_H -#define KQOAUTHREQUEST_XAUTH_P_H - -#include "kqoauthglobals.h" - -class KQOAuthRequest; -class KQOAUTH_EXPORT KQOAuthRequest_XAuthPrivate -{ -public: - KQOAuthRequest_XAuthPrivate(); - ~KQOAuthRequest_XAuthPrivate(); -}; - -#endif // KQOAUTHREQUEST_XAUTH_P_H diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthutils.cpp b/src/libtomahawk/thirdparty/kqoauth/kqoauthutils.cpp deleted file mode 100644 index d021385ef8..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthutils.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see - */ -#include -#include -#include - -#include -#include "kqoauthutils.h" - -QString KQOAuthUtils::hmac_sha1(const QString &message, const QString &key) -{ - QByteArray keyBytes = key.toAscii(); - int keyLength; // Lenght of key word - const int blockSize = 64; // Both MD5 and SHA-1 have a block size of 64. - - keyLength = keyBytes.size(); - // If key is longer than block size, we need to hash the key - if (keyLength > blockSize) { - QCryptographicHash hash(QCryptographicHash::Sha1); - hash.addData(keyBytes); - keyBytes = hash.result(); - } - - /* http://tools.ietf.org/html/rfc2104 - (1) */ - // Create the opad and ipad for the hash function. - QByteArray ipad; - QByteArray opad; - - ipad.fill( 0, blockSize); - opad.fill( 0, blockSize); - - ipad.replace(0, keyBytes.length(), keyBytes); - opad.replace(0, keyBytes.length(), keyBytes); - - /* http://tools.ietf.org/html/rfc2104 - (2) & (5) */ - for (int i=0; i<64; i++) { - ipad[i] = ipad[i] ^ 0x36; - opad[i] = opad[i] ^ 0x5c; - } - - QByteArray workArray; - workArray.clear(); - - workArray.append(ipad, 64); - /* http://tools.ietf.org/html/rfc2104 - (3) */ - workArray.append(message.toAscii()); - - - /* http://tools.ietf.org/html/rfc2104 - (4) */ - QByteArray sha1 = QCryptographicHash::hash(workArray, QCryptographicHash::Sha1); - - /* http://tools.ietf.org/html/rfc2104 - (6) */ - workArray.clear(); - workArray.append(opad, 64); - workArray.append(sha1); - - sha1.clear(); - - /* http://tools.ietf.org/html/rfc2104 - (7) */ - sha1 = QCryptographicHash::hash(workArray, QCryptographicHash::Sha1); - return QString(sha1.toBase64()); -} diff --git a/src/libtomahawk/thirdparty/kqoauth/kqoauthutils.h b/src/libtomahawk/thirdparty/kqoauth/kqoauthutils.h deleted file mode 100644 index db1f8840fd..0000000000 --- a/src/libtomahawk/thirdparty/kqoauth/kqoauthutils.h +++ /dev/null @@ -1,37 +0,0 @@ -/** - * KQOAuth - An OAuth authentication library for Qt. - * - * Author: Johan Paul (johan.paul@d-pointer.com) - * http://www.d-pointer.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * KQOAuth is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * In addition, as a special exception, KQOauth provides you certain additional - * rights. These rights are described in the Nokia Qt LGPL Exception - * version 1.1, included in the file LGPL_EXCEPTION.txt in this package. - * - * You should have received a copy of the GNU Lesser General Public License - * along with KQOAuth. If not, see - */ -#ifndef KQOAUTHUTILS_H -#define KQOAUTHUTILS_H - -#include "kqoauthglobals.h" - -class QString; -class KQOAUTH_EXPORT KQOAuthUtils -{ -public: - - static QString hmac_sha1(const QString &message, const QString &key); -}; - -#endif // KQOAUTHUTILS_H From f90e312c2adf57ff0d3f1372beac0a2d2e4d9186 Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Fri, 22 Mar 2013 08:43:38 +0100 Subject: [PATCH 56/76] Add licence and source for Tomahawk.bind Style correction. --- data/js/tomahawk.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/data/js/tomahawk.js b/data/js/tomahawk.js index 951c461128..64b10141ba 100644 --- a/data/js/tomahawk.js +++ b/data/js/tomahawk.js @@ -235,9 +235,9 @@ Tomahawk.syncRequest = function(url, extraHeaders) } xmlHttpRequest.send(null); - if (xmlHttpRequest.status == 200){ + if (xmlHttpRequest.status == 200) { return xmlHttpRequest.responseText; - }else if (xmlHttpRequest.readyState === 4) { + } else if (xmlHttpRequest.readyState === 4) { Tomahawk.log("Failed to do Get request: to: " + url); Tomahawk.log("Status Code was: " + xmlHttpRequest.status); } @@ -449,6 +449,11 @@ Tomahawk.sha256=function(s){ }; +/* + * Bind the function to be executed in the scope of the object oThis. + * Any copyright is dedicated to the Public Domain. + * Source : http://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind#Compatibility + */ if (!Function.prototype.bind) { Function.prototype.bind = function (oThis) { if (typeof this !== "function") { From c736a8b1b2036762df48646529370ae59f751473 Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Fri, 22 Mar 2013 10:33:24 +0100 Subject: [PATCH 57/76] Remove dropbox icon from Tomahawk. --- resources.qrc | 1 - src/libtomahawk/utils/TomahawkUtilsGui.cpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/resources.qrc b/resources.qrc index 9e19cb6836..f22787eab5 100644 --- a/resources.qrc +++ b/resources.qrc @@ -149,7 +149,6 @@ data/images/ok.svg data/images/tweet.svg data/images/widget-border.png - data/images/dropbox-icon.png data/images/refresh.svg diff --git a/src/libtomahawk/utils/TomahawkUtilsGui.cpp b/src/libtomahawk/utils/TomahawkUtilsGui.cpp index 28547344ea..7a7be966d3 100644 --- a/src/libtomahawk/utils/TomahawkUtilsGui.cpp +++ b/src/libtomahawk/utils/TomahawkUtilsGui.cpp @@ -705,7 +705,7 @@ defaultPixmap( ImageType type, ImageMode mode, const QSize& size ) pixmap = ImageRegistry::instance()->pixmap( RESPATH "images/spotify-sourceicon.svg", size ); break; case DropboxIcon: - pixmap = ImageRegistry::instance()->pixmap( RESPATH "images/dropbox-icon.png", size ); + pixmap = ImageRegistry::instance()->pixmap( RESPATH "images/dropbox-icon.svg", size ); break; case SoundcloudIcon: pixmap = ImageRegistry::instance()->pixmap( RESPATH "images/soundcloud.svg", size ); From a0bb904a93ac2c9e2c89765526d4241ab4dca91a Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Fri, 22 Mar 2013 11:06:27 +0100 Subject: [PATCH 58/76] Finish deleting of dropbox incon in tomahawk. --- src/libtomahawk/utils/TomahawkUtils.h | 1 - src/libtomahawk/utils/TomahawkUtilsGui.cpp | 3 --- 2 files changed, 4 deletions(-) diff --git a/src/libtomahawk/utils/TomahawkUtils.h b/src/libtomahawk/utils/TomahawkUtils.h index e2faee66fb..7f56f30403 100644 --- a/src/libtomahawk/utils/TomahawkUtils.h +++ b/src/libtomahawk/utils/TomahawkUtils.h @@ -113,7 +113,6 @@ namespace TomahawkUtils DropTopSongs, LastfmIcon, SpotifyIcon, - DropboxIcon, SoundcloudIcon, AccountNone, Starred, diff --git a/src/libtomahawk/utils/TomahawkUtilsGui.cpp b/src/libtomahawk/utils/TomahawkUtilsGui.cpp index 7a7be966d3..c444e21f04 100644 --- a/src/libtomahawk/utils/TomahawkUtilsGui.cpp +++ b/src/libtomahawk/utils/TomahawkUtilsGui.cpp @@ -704,9 +704,6 @@ defaultPixmap( ImageType type, ImageMode mode, const QSize& size ) case SpotifyIcon: pixmap = ImageRegistry::instance()->pixmap( RESPATH "images/spotify-sourceicon.svg", size ); break; - case DropboxIcon: - pixmap = ImageRegistry::instance()->pixmap( RESPATH "images/dropbox-icon.svg", size ); - break; case SoundcloudIcon: pixmap = ImageRegistry::instance()->pixmap( RESPATH "images/soundcloud.svg", size ); break; From 04906066520485592f9a21118210284e7375f9cf Mon Sep 17 00:00:00 2001 From: Tomahawk CI Date: Sat, 23 Mar 2013 01:17:00 +0100 Subject: [PATCH 59/76] Automatic merge of Transifex translations --- lang/tomahawk_sv.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lang/tomahawk_sv.ts b/lang/tomahawk_sv.ts index 19473cefad..a2f52b99a4 100644 --- a/lang/tomahawk_sv.ts +++ b/lang/tomahawk_sv.ts @@ -1359,7 +1359,7 @@ ansluta och strömma från dig? Script Resolver Warning: API call %1 returned data synchronously. - + Skript Resolver-varning: API-anrop %1 returnerade data synkront
@@ -3117,25 +3117,25 @@ Försök att ändra i filtrerna för att få en ny låtlista <br /><i>on</i> %1 %1 is an album name - + <br/><i>på</i> %1 %1<br /><i>by</i> %2%3. %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing - + %1<br /><i>av</i> %2%3. on "%1" %1 is an album name - + på "%1" "%1" by %2%3. %1 is a title, %2 is an artist and %3 is replaced by either the previous message or nothing - + "%1" av %2%3. From 2f98712382d979fbd51f40f5df99bc5d6533be6b Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sat, 23 Mar 2013 09:10:18 +0100 Subject: [PATCH 60/76] * Updated ChangeLog. --- ChangeLog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ChangeLog b/ChangeLog index 26a246c615..1c3e22b6c5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ Version 0.7.0: +Version 0.6.1: + * Improved stability. + * Improved UPnP detection and port-forwarding. + * Fixed scrolling behaviour of grid-views. + * Lots of small design tweaks and fixes. + Version 0.6.0: * Improved icon theme with vector graphics. * Higher resolution artist and album images. From eefea9471c2d46f1b22da8c0b159cf625d194ab8 Mon Sep 17 00:00:00 2001 From: Teo Mrnjavac Date: Sat, 23 Mar 2013 12:33:32 +0100 Subject: [PATCH 61/76] Fix GridView layout bug on some GTK styles. --- src/libtomahawk/playlist/GridView.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/libtomahawk/playlist/GridView.cpp b/src/libtomahawk/playlist/GridView.cpp index 1b4931a7d4..b41bb986e2 100644 --- a/src/libtomahawk/playlist/GridView.cpp +++ b/src/libtomahawk/playlist/GridView.cpp @@ -232,12 +232,10 @@ GridView::verifySize() if ( !autoResize() || !m_model ) return; -#ifdef Q_WS_X11 -// int scrollbar = verticalScrollBar()->isVisible() ? verticalScrollBar()->width() + 16 : 0; - int scrollbar = 0; verticalScrollBar()->rect().width(); -#else int scrollbar = verticalScrollBar()->rect().width(); -#endif + + if ( rect().width() - contentsRect().width() > scrollbar ) //HACK: if the contentsRect includes the scrollbar + scrollbar = 0; //don't count it any more const int rectWidth = contentsRect().width() - scrollbar - 3; const int itemWidth = 160; @@ -274,12 +272,10 @@ GridView::layoutItems() { if ( autoFitItems() && m_model ) { -#ifdef Q_WS_X11 -// int scrollbar = verticalScrollBar()->isVisible() ? verticalScrollBar()->width() + 16 : 0; - int scrollbar = 0; verticalScrollBar()->rect().width(); -#else int scrollbar = verticalScrollBar()->rect().width(); -#endif + + if ( rect().width() - contentsRect().width() >= scrollbar ) //HACK: if the contentsRect includes the scrollbar + scrollbar = 0; //don't count it any more const int rectWidth = contentsRect().width() - scrollbar - 3; const int itemWidth = 160; From fb11624fb29841c0a632e9401c6e2eaeaf7ddd6e Mon Sep 17 00:00:00 2001 From: Stefan Derkits Date: Sat, 23 Mar 2013 17:20:17 +0100 Subject: [PATCH 62/76] Implement locking mechanism to only allow one thread to contact echonest for loading Styles, Moods & Genres --- .../dynamic/echonest/EchonestGenerator.cpp | 110 ++++++++++++------ .../dynamic/echonest/EchonestGenerator.h | 9 +- 2 files changed, 84 insertions(+), 35 deletions(-) diff --git a/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp b/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp index ca4a87aefe..126b425bd7 100644 --- a/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp +++ b/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp @@ -29,6 +29,7 @@ #include "SourceList.h" #include #include +#include #include using namespace Tomahawk; @@ -41,6 +42,10 @@ QNetworkReply* EchonestGenerator::s_moodsJob = 0; QNetworkReply* EchonestGenerator::s_stylesJob = 0; QNetworkReply* EchonestGenerator::s_genresJob = 0; +static QMutex s_moods_mutex; +static QMutex s_styles_mutex; +static QMutex s_genres_mutex; + CatalogManager* EchonestGenerator::s_catalogs = 0; @@ -615,61 +620,95 @@ EchonestGenerator::loadStylesMoodsAndGenres() { if( !s_styles.isEmpty() && !s_moods.isEmpty() && !s_genres.isEmpty() ) return; + + loadStyles(); + loadMoods(); + loadGenres(); +} + +void +EchonestGenerator::loadStyles() +{ if ( s_styles.isEmpty() ) { - QVariant styles = TomahawkUtils::Cache::instance()->getData( "EchonesGenerator", "styles" ); - if ( styles.isValid() && styles.canConvert< QStringList >() ) + if ( s_styles_mutex.tryLock() ) { - s_styles = styles.toStringList(); + s_styles_mutex.unlock(); + QVariant styles = TomahawkUtils::Cache::instance()->getData( "EchonesGenerator", "styles" ); + if ( styles.isValid() && styles.canConvert< QStringList >() ) + { + s_styles = styles.toStringList(); + } + else + { + s_styles_mutex.lock(); + tLog() << "Styles not in cache or too old, refetching styles ..."; + s_stylesJob = Echonest::Artist::listTerms( "style" ); + connect( s_stylesJob, SIGNAL( finished() ), this, SLOT( stylesReceived() ) ); + } } else { - tLog() << "Styles not in cache or too old, refetching styles ..."; - s_stylesJob = Echonest::Artist::listTerms( "style" ); - connect( s_stylesJob, SIGNAL( finished() ), this, SLOT( stylesReceived() ) ); + connect( this, SIGNAL( stylesSaved() ), this, SLOT( loadStyles() ) ); } } +} +void +EchonestGenerator::loadMoods() +{ if ( s_moods.isEmpty() ) { - QVariant moods = TomahawkUtils::Cache::instance()->getData( "EchonesGenerator", "moods" ); - if ( moods.isValid() && moods.canConvert< QStringList >() ) { - s_moods = moods.toStringList(); + if ( s_moods_mutex.tryLock() ) + { + s_moods_mutex.unlock(); + QVariant moods = TomahawkUtils::Cache::instance()->getData( "EchonesGenerator", "moods" ); + if ( moods.isValid() && moods.canConvert< QStringList >() ) { + s_moods = moods.toStringList(); + } + else + { + s_moods_mutex.lock(); + tLog() << "Moods not in cache or too old, refetching moods ..."; + s_moodsJob = Echonest::Artist::listTerms( "mood" ); + connect( s_moodsJob, SIGNAL( finished() ), this, SLOT( moodsReceived() ) ); + } } else { - tLog() << "Moods not in cache or too old, refetching moods ..."; - s_moodsJob = Echonest::Artist::listTerms( "mood" ); - connect( s_moodsJob, SIGNAL( finished() ), this, SLOT( moodsReceived() ) ); + connect( this, SIGNAL( moodsSaved() ), this, SLOT( loadMoods() ) ); } } +} +void +EchonestGenerator::loadGenres() +{ if ( s_genres.isEmpty() ) { - QVariant genres = TomahawkUtils::Cache::instance()->getData( "EchonesGenerator", "genres" ); - if ( genres.isValid() && genres.canConvert< QStringList >() ) + if ( s_genres_mutex.tryLock() ) { - s_genres = genres.toStringList(); + s_genres_mutex.unlock(); + QVariant genres = TomahawkUtils::Cache::instance()->getData( "EchonesGenerator", "genres" ); + if ( genres.isValid() && genres.canConvert< QStringList >() ) + { + s_genres = genres.toStringList(); + } + else + { + s_genres_mutex.lock(); + tLog() << "Genres not in cache or too old, refetching genres ..."; + s_genresJob = Echonest::Artist::fetchGenres(); + connect( s_genresJob, SIGNAL( finished() ), this, SLOT( genresReceived() ) ); + } } else { - tLog() << "Genres not in cache or too old, refetching genres ..."; - s_genresJob = Echonest::Artist::fetchGenres(); - connect( s_genresJob, SIGNAL( finished() ), this, SLOT( genresReceived() ) ); + connect( this, SIGNAL( genresSaved() ), this, SLOT( loadGenres() ) ); } } } -void -EchonestGenerator::saveStylesMoodsAndGenres() -{ - TomahawkUtils::Cache::instance()->putData( "EchonesGenerator", 1209600000 /* 2 weeks */, "moods", QVariant::fromValue< QStringList >( s_moods ) ); - TomahawkUtils::Cache::instance()->putData( "EchonesGenerator", 1209600000 /* 2 weeks */, "styles", QVariant::fromValue< QStringList >( s_styles ) ); - TomahawkUtils::Cache::instance()->putData( "EchonesGenerator", 1209600000 /* 2 weeks */, "genres", QVariant::fromValue< QStringList >( s_genres ) ); -} - - - QStringList EchonestGenerator::moods() { @@ -693,8 +732,9 @@ EchonestGenerator::moodsReceived() } s_moodsJob = 0; - if( !s_styles.isEmpty() && !s_genres.isEmpty() ) - saveStylesMoodsAndGenres(); + TomahawkUtils::Cache::instance()->putData( "EchonesGenerator", 1209600000 /* 2 weeks */, "moods", QVariant::fromValue< QStringList >( s_moods ) ); + s_moods_mutex.unlock(); + emit moodsSaved(); } @@ -721,8 +761,9 @@ EchonestGenerator::stylesReceived() } s_stylesJob = 0; - if( !s_moods.isEmpty() && !s_styles.isEmpty() ) - saveStylesMoodsAndGenres(); + TomahawkUtils::Cache::instance()->putData( "EchonesGenerator", 1209600000 /* 2 weeks */, "styles", QVariant::fromValue< QStringList >( s_styles ) ); + s_styles_mutex.unlock(); + emit stylesSaved(); } QStringList @@ -747,6 +788,7 @@ EchonestGenerator::genresReceived() } s_genresJob = 0; - if( !s_moods.isEmpty() && !s_styles.isEmpty() ) - saveStylesMoodsAndGenres(); + TomahawkUtils::Cache::instance()->putData( "EchonesGenerator", 1209600000 /* 2 weeks */, "genres", QVariant::fromValue< QStringList >( s_genres ) ); + s_genres_mutex.unlock(); + emit genresSaved(); } diff --git a/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.h b/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.h index 7e0822add8..5f8777abb0 100644 --- a/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.h +++ b/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.h @@ -90,6 +90,10 @@ class DLLEXPORT EchonestGenerator : public GeneratorInterface signals: void paramsGenerated( const Echonest::DynamicPlaylist::PlaylistParams& ); + void stylesSaved(); + void moodsSaved(); + void genresSaved(); + private slots: void staticFinished(); void dynamicStarted(); @@ -98,6 +102,10 @@ private slots: void doGenerate( const Echonest::DynamicPlaylist::PlaylistParams& params ); void doStartOnDemand( const Echonest::DynamicPlaylist::PlaylistParams& params ); + void loadStyles(); + void loadMoods(); + void loadGenres(); + void stylesReceived(); void moodsReceived(); void genresReceived(); @@ -113,7 +121,6 @@ private slots: bool onlyThisArtistType( Echonest::DynamicPlaylist::ArtistTypeEnum type ) const throw( std::runtime_error ); void loadStylesMoodsAndGenres(); - void saveStylesMoodsAndGenres(); Echonest::DynamicPlaylist* m_dynPlaylist; QPixmap m_logo; From 677e8149f26162eea7466ece5599317e78d222ee Mon Sep 17 00:00:00 2001 From: Stefan Derkits Date: Sat, 23 Mar 2013 20:53:42 +0100 Subject: [PATCH 63/76] use ReadWriteLock instead of Mutex --- .../dynamic/echonest/EchonestGenerator.cpp | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp b/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp index 126b425bd7..fdaf4df40f 100644 --- a/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp +++ b/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp @@ -29,7 +29,7 @@ #include "SourceList.h" #include #include -#include +#include #include using namespace Tomahawk; @@ -42,9 +42,9 @@ QNetworkReply* EchonestGenerator::s_moodsJob = 0; QNetworkReply* EchonestGenerator::s_stylesJob = 0; QNetworkReply* EchonestGenerator::s_genresJob = 0; -static QMutex s_moods_mutex; -static QMutex s_styles_mutex; -static QMutex s_genres_mutex; +static QReadWriteLock s_moods_lock; +static QReadWriteLock s_styles_lock; +static QReadWriteLock s_genres_lock; CatalogManager* EchonestGenerator::s_catalogs = 0; @@ -631,17 +631,17 @@ EchonestGenerator::loadStyles() { if ( s_styles.isEmpty() ) { - if ( s_styles_mutex.tryLock() ) + if ( s_styles_lock.tryLockForRead() ) { - s_styles_mutex.unlock(); QVariant styles = TomahawkUtils::Cache::instance()->getData( "EchonesGenerator", "styles" ); + s_styles_lock.unlock(); if ( styles.isValid() && styles.canConvert< QStringList >() ) { s_styles = styles.toStringList(); } else { - s_styles_mutex.lock(); + s_styles_lock.lockForWrite(); tLog() << "Styles not in cache or too old, refetching styles ..."; s_stylesJob = Echonest::Artist::listTerms( "style" ); connect( s_stylesJob, SIGNAL( finished() ), this, SLOT( stylesReceived() ) ); @@ -659,16 +659,16 @@ EchonestGenerator::loadMoods() { if ( s_moods.isEmpty() ) { - if ( s_moods_mutex.tryLock() ) + if ( s_moods_lock.tryLockForRead() ) { - s_moods_mutex.unlock(); QVariant moods = TomahawkUtils::Cache::instance()->getData( "EchonesGenerator", "moods" ); + s_moods_lock.unlock(); if ( moods.isValid() && moods.canConvert< QStringList >() ) { s_moods = moods.toStringList(); } else { - s_moods_mutex.lock(); + s_moods_lock.lockForWrite(); tLog() << "Moods not in cache or too old, refetching moods ..."; s_moodsJob = Echonest::Artist::listTerms( "mood" ); connect( s_moodsJob, SIGNAL( finished() ), this, SLOT( moodsReceived() ) ); @@ -686,17 +686,17 @@ EchonestGenerator::loadGenres() { if ( s_genres.isEmpty() ) { - if ( s_genres_mutex.tryLock() ) + if ( s_genres_lock.tryLockForRead() ) { - s_genres_mutex.unlock(); QVariant genres = TomahawkUtils::Cache::instance()->getData( "EchonesGenerator", "genres" ); + s_genres_lock.unlock(); if ( genres.isValid() && genres.canConvert< QStringList >() ) { s_genres = genres.toStringList(); } else { - s_genres_mutex.lock(); + s_genres_lock.lockForWrite(); tLog() << "Genres not in cache or too old, refetching genres ..."; s_genresJob = Echonest::Artist::fetchGenres(); connect( s_genresJob, SIGNAL( finished() ), this, SLOT( genresReceived() ) ); @@ -733,7 +733,7 @@ EchonestGenerator::moodsReceived() s_moodsJob = 0; TomahawkUtils::Cache::instance()->putData( "EchonesGenerator", 1209600000 /* 2 weeks */, "moods", QVariant::fromValue< QStringList >( s_moods ) ); - s_moods_mutex.unlock(); + s_moods_lock.unlock(); emit moodsSaved(); } @@ -762,7 +762,7 @@ EchonestGenerator::stylesReceived() s_stylesJob = 0; TomahawkUtils::Cache::instance()->putData( "EchonesGenerator", 1209600000 /* 2 weeks */, "styles", QVariant::fromValue< QStringList >( s_styles ) ); - s_styles_mutex.unlock(); + s_styles_lock.unlock(); emit stylesSaved(); } @@ -789,6 +789,6 @@ EchonestGenerator::genresReceived() s_genresJob = 0; TomahawkUtils::Cache::instance()->putData( "EchonesGenerator", 1209600000 /* 2 weeks */, "genres", QVariant::fromValue< QStringList >( s_genres ) ); - s_genres_mutex.unlock(); + s_genres_lock.unlock(); emit genresSaved(); } From 6131f5ed507cc9993688b3d87663648827d17e92 Mon Sep 17 00:00:00 2001 From: Tomahawk CI Date: Sun, 24 Mar 2013 01:44:29 +0100 Subject: [PATCH 64/76] Automatic merge of Transifex translations --- lang/tomahawk_ar.ts | 35 +++++++++++++++----------- lang/tomahawk_bg.ts | 35 +++++++++++++++----------- lang/tomahawk_bn_IN.ts | 35 +++++++++++++++----------- lang/tomahawk_ca.ts | 35 +++++++++++++++----------- lang/tomahawk_ca@valencia.ts | 35 +++++++++++++++----------- lang/tomahawk_cs.ts | 35 +++++++++++++++----------- lang/tomahawk_da.ts | 35 +++++++++++++++----------- lang/tomahawk_de.ts | 35 +++++++++++++++----------- lang/tomahawk_el.ts | 35 +++++++++++++++----------- lang/tomahawk_en.ts | 35 +++++++++++++++----------- lang/tomahawk_es.ts | 35 +++++++++++++++----------- lang/tomahawk_fi.ts | 35 +++++++++++++++----------- lang/tomahawk_fr.ts | 35 +++++++++++++++----------- lang/tomahawk_gl.ts | 35 +++++++++++++++----------- lang/tomahawk_hi_IN.ts | 35 +++++++++++++++----------- lang/tomahawk_hu.ts | 35 +++++++++++++++----------- lang/tomahawk_it.ts | 35 +++++++++++++++----------- lang/tomahawk_ja.ts | 35 +++++++++++++++----------- lang/tomahawk_lt.ts | 35 +++++++++++++++----------- lang/tomahawk_pl.ts | 35 +++++++++++++++----------- lang/tomahawk_pt_BR.ts | 35 +++++++++++++++----------- lang/tomahawk_ru.ts | 35 +++++++++++++++----------- lang/tomahawk_sv.ts | 49 ++++++++++++++++++++---------------- lang/tomahawk_tr.ts | 35 +++++++++++++++----------- lang/tomahawk_zh_CN.ts | 35 +++++++++++++++----------- lang/tomahawk_zh_TW.ts | 35 +++++++++++++++----------- 26 files changed, 527 insertions(+), 397 deletions(-) diff --git a/lang/tomahawk_ar.ts b/lang/tomahawk_ar.ts index 99235f06f4..c9ea64676f 100644 --- a/lang/tomahawk_ar.ts +++ b/lang/tomahawk_ar.ts @@ -369,17 +369,17 @@ connect and stream from you? AudioEngine - + Sorry, Tomahawk couldn't find the track '%1' by %2 نعتذر، لم نستطيع إيجاد الأغنية '%1' ل%2 - + Sorry, Tomahawk couldn't find the artist '%1' نعتذر، لم نستطيع إيجاد الفنان '%1' - + Sorry, Tomahawk couldn't find the album '%1' by %2 نعتذر، لم نستطيع إيجاد الألبوم '%1' ل%2 @@ -1356,9 +1356,9 @@ connect and stream from you? QtScriptResolver - - - + + + Script Resolver Warning: API call %1 returned data synchronously. تحذير محلل النصي: أعاد ال API البيانات %1 بشكل متزامن. @@ -1422,7 +1422,7 @@ connect and stream from you? ScriptEngine - + Script Resolver Error: %1 %2 %3 %4 خطأ محلل النصي: %1 %2 %3 %4 @@ -1501,12 +1501,17 @@ connect and stream from you? تثبيت محلل من ملف - + + Tomahawk Resolvers (*.axe *.js);;All files (*) + + + + Delete all Access Control entries? حذف كافة بيانات التحكم بالوصول؟ - + Do you really want to delete all Access Control entries? You will be asked for a decision again for each peer that you connect to. هل فعلا تريد حذف جميع بيانات التحكم بالوصول؟ سوف يطلب منك اتخاذ القرار مجددا لكل ند على اتصال به. @@ -2073,22 +2078,22 @@ connect and stream from you? إزالة - + %1 downloads تحميل %1 - + Online متصل - + Connecting... جاري الاتصال... - + Offline غير متصل @@ -2096,12 +2101,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required مطلوب تثبيت يدوي - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 لسوء الحظ، التثبيت التلقائي لهذا المحلل لم يتوفر بعد على منصتك. <br /><br /> الرجاء إستخدام " التثبيت من الملف" أعلاه، بواسطة جلبه من توزيعتك أو تجميعه بنفسك. ويمكن الاطلاع على مزيد من التعليمات هنا: <br /><br />http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_bg.ts b/lang/tomahawk_bg.ts index 63c03d0477..12f0b73d16 100644 --- a/lang/tomahawk_bg.ts +++ b/lang/tomahawk_bg.ts @@ -368,17 +368,17 @@ connect and stream from you? AudioEngine - + Sorry, Tomahawk couldn't find the track '%1' by %2 Съжалявам. Не успявам да открия изпълнение '%1' от '%2' - + Sorry, Tomahawk couldn't find the artist '%1' Съжалявам, но не откривам '%1' - + Sorry, Tomahawk couldn't find the album '%1' by %2 Съжалявам, но не откривам албум с име '%1' от '%2' @@ -1364,9 +1364,9 @@ Tomahawk създаде доклад относно това и изпращай QtScriptResolver - - - + + + Script Resolver Warning: API call %1 returned data synchronously. @@ -1430,7 +1430,7 @@ Tomahawk създаде доклад относно това и изпращай ScriptEngine - + Script Resolver Error: %1 %2 %3 %4 Грешка на скриптът за извличане на данни: %1 %2 %3 %4 @@ -1509,12 +1509,17 @@ Tomahawk създаде доклад относно това и изпращай Инсталирай услуги за търсене от файл - + + Tomahawk Resolvers (*.axe *.js);;All files (*) + + + + Delete all Access Control entries? Изтриване на всички данни за достъп? - + Do you really want to delete all Access Control entries? You will be asked for a decision again for each peer that you connect to. Наистина ли желаеш да изтриеш всички данни за достъп? Ще бъдеш питан отново за даване на достъп за всяка връзка. @@ -2085,22 +2090,22 @@ Tomahawk създаде доклад относно това и изпращай Премахни - + %1 downloads %1 сваляния - + Online На линия - + Connecting... Свързване... - + Offline Извън линия @@ -2108,12 +2113,12 @@ Tomahawk създаде доклад относно това и изпращай Tomahawk::Accounts::AccountModel - + Manual Install Required Изисква се ръчно инсталиране - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 За съжаление, автоматичното инсталиране на този компонент е деактивирано за твоята платформа. <br /><br /> diff --git a/lang/tomahawk_bn_IN.ts b/lang/tomahawk_bn_IN.ts index bd418d14da..cc02cec9d2 100644 --- a/lang/tomahawk_bn_IN.ts +++ b/lang/tomahawk_bn_IN.ts @@ -368,17 +368,17 @@ connect and stream from you? AudioEngine - + Sorry, Tomahawk couldn't find the track '%1' by %2 - + Sorry, Tomahawk couldn't find the artist '%1' - + Sorry, Tomahawk couldn't find the album '%1' by %2 @@ -1353,9 +1353,9 @@ connect and stream from you? QtScriptResolver - - - + + + Script Resolver Warning: API call %1 returned data synchronously. @@ -1419,7 +1419,7 @@ connect and stream from you? ScriptEngine - + Script Resolver Error: %1 %2 %3 %4 @@ -1498,12 +1498,17 @@ connect and stream from you? - + + Tomahawk Resolvers (*.axe *.js);;All files (*) + + + + Delete all Access Control entries? - + Do you really want to delete all Access Control entries? You will be asked for a decision again for each peer that you connect to. @@ -2070,22 +2075,22 @@ connect and stream from you? - + %1 downloads - + Online - + Connecting... - + Offline @@ -2093,12 +2098,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_ca.ts b/lang/tomahawk_ca.ts index 1077f0b3fe..874f7b6a6c 100644 --- a/lang/tomahawk_ca.ts +++ b/lang/tomahawk_ca.ts @@ -368,17 +368,17 @@ connect and stream from you? AudioEngine - + Sorry, Tomahawk couldn't find the track '%1' by %2 No s'ha trobat la cançó «%1» de «%2» - + Sorry, Tomahawk couldn't find the artist '%1' No s'ha trobat l'artista «%1» - + Sorry, Tomahawk couldn't find the album '%1' by %2 No s'ha trobat l'àlbum «%1» de «%2» @@ -1354,9 +1354,9 @@ connect and stream from you? QtScriptResolver - - - + + + Script Resolver Warning: API call %1 returned data synchronously. @@ -1420,7 +1420,7 @@ connect and stream from you? ScriptEngine - + Script Resolver Error: %1 %2 %3 %4 Error de resolució de l'script: %1 %2 %3 %4 @@ -1499,12 +1499,17 @@ connect and stream from you? Instal·la un Resolver des d'un fitxer - + + Tomahawk Resolvers (*.axe *.js);;All files (*) + + + + Delete all Access Control entries? Voleu eliminar totes les entrades d'Access Control? - + Do you really want to delete all Access Control entries? You will be asked for a decision again for each peer that you connect to. Realment voleu eliminar totes les entrades de l'Access Control? Se us demanarà per una decisió una altra vegada per cada recurs al que us connecteu. @@ -2074,22 +2079,22 @@ i emissores basades en els vostres gusts musicals. Esborra - + %1 downloads %1 descàrregues - + Online En Línia - + Connecting... Connectant-se... - + Offline Fora de Línia @@ -2097,12 +2102,12 @@ i emissores basades en els vostres gusts musicals. Tomahawk::Accounts::AccountModel - + Manual Install Required Es requereix una instal·lació manual - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 La instal·lació automàtica d'aquest resoludor no està disponible o està desactivada per a la vostra plataforma.<br /><br />Feu servir «Instal·la des d'un fitxer», obtenint-lo des de la vostra distribució o compilant-lo. Trobareu més instruccions aquí:<br /><br />http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_ca@valencia.ts b/lang/tomahawk_ca@valencia.ts index 73dbb060c7..4d232f2c23 100644 --- a/lang/tomahawk_ca@valencia.ts +++ b/lang/tomahawk_ca@valencia.ts @@ -368,17 +368,17 @@ connect and stream from you? AudioEngine - + Sorry, Tomahawk couldn't find the track '%1' by %2 No s'ha trobat la cançó «%1» de «%2» - + Sorry, Tomahawk couldn't find the artist '%1' No s'ha trobat l'artista «%1» - + Sorry, Tomahawk couldn't find the album '%1' by %2 No s'ha trobat l'àlbum «%1» de «%2» @@ -1354,9 +1354,9 @@ connect and stream from you? QtScriptResolver - - - + + + Script Resolver Warning: API call %1 returned data synchronously. @@ -1420,7 +1420,7 @@ connect and stream from you? ScriptEngine - + Script Resolver Error: %1 %2 %3 %4 Error de resolució de l'script: %1 %2 %3 %4 @@ -1499,12 +1499,17 @@ connect and stream from you? Instal·la un Resolver des d'un fitxer - + + Tomahawk Resolvers (*.axe *.js);;All files (*) + + + + Delete all Access Control entries? Voleu eliminar totes les entrades d'Access Control? - + Do you really want to delete all Access Control entries? You will be asked for a decision again for each peer that you connect to. Realment voleu eliminar totes les entrades de l'Access Control? Se vos demanarà per una decisió una altra vegada per cada recurs al que vos connecteu. @@ -2074,22 +2079,22 @@ i emissores basades en els vostres gusts musicals. Esborra - + %1 downloads %1 descàrregues - + Online En Línia - + Connecting... Connectant-se... - + Offline Fora de Línia @@ -2097,12 +2102,12 @@ i emissores basades en els vostres gusts musicals. Tomahawk::Accounts::AccountModel - + Manual Install Required Es requereix una instal·lació manual - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 La instal·lació automàtica d'este resoludor no està disponible o està desactivada per a la vostra plataforma.<br /><br />Feu servir «Instal·la des d'un fitxer», obtenint-lo des de la vostra distribució o compilant-lo. Trobareu més instruccions ací:<br /><br />http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_cs.ts b/lang/tomahawk_cs.ts index a67ba36424..5829779911 100644 --- a/lang/tomahawk_cs.ts +++ b/lang/tomahawk_cs.ts @@ -369,17 +369,17 @@ se s vámi spojil? AudioEngine - + Sorry, Tomahawk couldn't find the track '%1' by %2 Promiňte, Tomahawku se nepodařilo najít skladbu '%1' od %2 - + Sorry, Tomahawk couldn't find the artist '%1' Promiňte, Tomahawku se nepodařilo najít umělce '%1' - + Sorry, Tomahawk couldn't find the album '%1' by %2 Promiňte, Tomahawku se nepodařilo najít album '%1' od %2 @@ -1355,9 +1355,9 @@ se s vámi spojil? QtScriptResolver - - - + + + Script Resolver Warning: API call %1 returned data synchronously. Varování řešitele skriptu: Volání API %1 vrátilo data synchronně. @@ -1421,7 +1421,7 @@ se s vámi spojil? ScriptEngine - + Script Resolver Error: %1 %2 %3 %4 Chyba řešitele skriptu: %1 %2 %3 %4 @@ -1500,12 +1500,17 @@ se s vámi spojil? Instalovat řešitele ze souboru - + + Tomahawk Resolvers (*.axe *.js);;All files (*) + + + + Delete all Access Control entries? Smazat všechna udělená přístupová oprávnění? - + Do you really want to delete all Access Control entries? You will be asked for a decision again for each peer that you connect to. Opravdu chcete smazat všechna nastavení přístupových práv? Budete znovu dotazován na nastavení přístupových oprávnění pro každé spojení. @@ -2072,22 +2077,22 @@ se s vámi spojil? Odstranit - + %1 downloads %1 stažení - + Online Připojený - + Connecting... Připojuje se... - + Offline Nepřipojený @@ -2095,12 +2100,12 @@ se s vámi spojil? Tomahawk::Accounts::AccountModel - + Manual Install Required Je potřeba ruční instalace - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 Bohužel není instalace tohoto řešitele ve vašem systému možná.<br/><br/>Použijte, prosím, "Instalovat ze souboru" a nainstalujte jej ručněl. Další informace naleznete zde:<br/><br/>http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_da.ts b/lang/tomahawk_da.ts index 96e60bb123..c7ec8e67d6 100644 --- a/lang/tomahawk_da.ts +++ b/lang/tomahawk_da.ts @@ -368,17 +368,17 @@ connect and stream from you? AudioEngine - + Sorry, Tomahawk couldn't find the track '%1' by %2 - + Sorry, Tomahawk couldn't find the artist '%1' - + Sorry, Tomahawk couldn't find the album '%1' by %2 @@ -1354,9 +1354,9 @@ connect and stream from you? QtScriptResolver - - - + + + Script Resolver Warning: API call %1 returned data synchronously. @@ -1420,7 +1420,7 @@ connect and stream from you? ScriptEngine - + Script Resolver Error: %1 %2 %3 %4 @@ -1499,12 +1499,17 @@ connect and stream from you? Installer resolver fra fil - + + Tomahawk Resolvers (*.axe *.js);;All files (*) + + + + Delete all Access Control entries? - + Do you really want to delete all Access Control entries? You will be asked for a decision again for each peer that you connect to. @@ -2071,22 +2076,22 @@ connect and stream from you? - + %1 downloads %1 downloads - + Online Online - + Connecting... Forbinder... - + Offline Offline @@ -2094,12 +2099,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_de.ts b/lang/tomahawk_de.ts index a08ab0be05..699c0ac799 100644 --- a/lang/tomahawk_de.ts +++ b/lang/tomahawk_de.ts @@ -369,17 +369,17 @@ erlauben sich mit dir zu verbinden? AudioEngine - + Sorry, Tomahawk couldn't find the track '%1' by %2 Sorry, Tomahawk konnte '%1' von %2 nicht finden - + Sorry, Tomahawk couldn't find the artist '%1' Sorry, Tomahawk konnte den Künstler '%1' nicht finden - + Sorry, Tomahawk couldn't find the album '%1' by %2 Sorry, Tomahawk konnte das Album '%1' von %2 nicht finden @@ -1355,9 +1355,9 @@ erlauben sich mit dir zu verbinden? QtScriptResolver - - - + + + Script Resolver Warning: API call %1 returned data synchronously. @@ -1421,7 +1421,7 @@ erlauben sich mit dir zu verbinden? ScriptEngine - + Script Resolver Error: %1 %2 %3 %4 Script Resolver Fehler: %1 %2 %3 %4 @@ -1500,12 +1500,17 @@ erlauben sich mit dir zu verbinden? Installiere Resolver Datei - + + Tomahawk Resolvers (*.axe *.js);;All files (*) + + + + Delete all Access Control entries? Alle erteilten Zugriffsrechte löschen? - + Do you really want to delete all Access Control entries? You will be asked for a decision again for each peer that you connect to. Willst du wirklich alle Zugriffseinstellungen zurücksetzen? Du wirst für alle Verbindungen erneut nach Zugriffseinstellungen gefragt werden. @@ -2072,22 +2077,22 @@ erlauben sich mit dir zu verbinden? Entfernen - + %1 downloads %1 Downloads - + Online Verbunden - + Connecting... Verbinde... - + Offline Nicht Verbunden @@ -2095,12 +2100,12 @@ erlauben sich mit dir zu verbinden? Tomahawk::Accounts::AccountModel - + Manual Install Required Manuelle Installation benötigt - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 Leider ist die automatische Installation dieses Resolvers nicht auf deinem System möglich.<br/><br/>Bitte benutze "Installiere Datei" und installiere ihn manuell. Weitere Informationen findest du hier:<br/><br/>http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_el.ts b/lang/tomahawk_el.ts index cd88ec7cef..7e5097ae45 100644 --- a/lang/tomahawk_el.ts +++ b/lang/tomahawk_el.ts @@ -368,17 +368,17 @@ connect and stream from you? AudioEngine - + Sorry, Tomahawk couldn't find the track '%1' by %2 - + Sorry, Tomahawk couldn't find the artist '%1' - + Sorry, Tomahawk couldn't find the album '%1' by %2 @@ -1354,9 +1354,9 @@ connect and stream from you? QtScriptResolver - - - + + + Script Resolver Warning: API call %1 returned data synchronously. @@ -1420,7 +1420,7 @@ connect and stream from you? ScriptEngine - + Script Resolver Error: %1 %2 %3 %4 @@ -1499,12 +1499,17 @@ connect and stream from you? Εγκατάσταση επιλυτή από αρχείο - + + Tomahawk Resolvers (*.axe *.js);;All files (*) + + + + Delete all Access Control entries? - + Do you really want to delete all Access Control entries? You will be asked for a decision again for each peer that you connect to. @@ -2071,22 +2076,22 @@ connect and stream from you? - + %1 downloads %1 λήψεις - + Online Συνεδεμένος - + Connecting... Σύνδεση... - + Offline Εκτός Σύνδεσης @@ -2094,12 +2099,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required Απαιτείται Χειροκίνητη Εγκατάσταση - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_en.ts b/lang/tomahawk_en.ts index a71abd63d7..bdad3b37de 100644 --- a/lang/tomahawk_en.ts +++ b/lang/tomahawk_en.ts @@ -369,17 +369,17 @@ connect and stream from you? AudioEngine - + Sorry, Tomahawk couldn't find the track '%1' by %2 Sorry, Tomahawk couldn't find the track '%1' by %2 - + Sorry, Tomahawk couldn't find the artist '%1' Sorry, Tomahawk couldn't find the artist '%1' - + Sorry, Tomahawk couldn't find the album '%1' by %2 Sorry, Tomahawk couldn't find the album '%1' by %2 @@ -1355,9 +1355,9 @@ connect and stream from you? QtScriptResolver - - - + + + Script Resolver Warning: API call %1 returned data synchronously. Script Resolver Warning: API call %1 returned data synchronously. @@ -1421,7 +1421,7 @@ connect and stream from you? ScriptEngine - + Script Resolver Error: %1 %2 %3 %4 Script Resolver Error: %1 %2 %3 %4 @@ -1500,12 +1500,17 @@ connect and stream from you? Install resolver from file - + + Tomahawk Resolvers (*.axe *.js);;All files (*) + Tomahawk Resolvers (*.axe *.js);;All files (*) + + + Delete all Access Control entries? Delete all Access Control entries? - + Do you really want to delete all Access Control entries? You will be asked for a decision again for each peer that you connect to. Do you really want to delete all Access Control entries? You will be asked for a decision again for each peer that you connect to. @@ -2075,22 +2080,22 @@ connect and stream from you? Remove - + %1 downloads %1 downloads - + Online Online - + Connecting... Connecting... - + Offline Offline @@ -2098,12 +2103,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required Manual Install Required - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_es.ts b/lang/tomahawk_es.ts index ca50078a11..75c0039dca 100644 --- a/lang/tomahawk_es.ts +++ b/lang/tomahawk_es.ts @@ -369,17 +369,17 @@ conectarse a usted y transmitir música? AudioEngine - + Sorry, Tomahawk couldn't find the track '%1' by %2 Tomahawk no pudo encontrar la pista '%1' de %2 - + Sorry, Tomahawk couldn't find the artist '%1' Tomahawk no pudo encontrar el artista '%1' - + Sorry, Tomahawk couldn't find the album '%1' by %2 Tomahawk no pudo encontrar el álbum '%1' de %2 @@ -1355,9 +1355,9 @@ conectarse a usted y transmitir música? QtScriptResolver - - - + + + Script Resolver Warning: API call %1 returned data synchronously. @@ -1421,7 +1421,7 @@ conectarse a usted y transmitir música? ScriptEngine - + Script Resolver Error: %1 %2 %3 %4 Error del resolutor de script: %1 %2 %3 %4 @@ -1500,12 +1500,17 @@ conectarse a usted y transmitir música? Instalar un servicio desde un fichero - + + Tomahawk Resolvers (*.axe *.js);;All files (*) + + + + Delete all Access Control entries? ¿Eliminar todas las fuentes del Control de acceso? - + Do you really want to delete all Access Control entries? You will be asked for a decision again for each peer that you connect to. ¿De verdad quiere borrar todo el Control de acceso de las fuentes? Será preguntado por cada fuente a la que se conecte. @@ -2075,22 +2080,22 @@ y estaciones basadas en sus gustos personales. Eliminar - + %1 downloads %1 descargas - + Online Conectado - + Connecting... Conectando… - + Offline Desconectado @@ -2098,12 +2103,12 @@ y estaciones basadas en sus gustos personales. Tomahawk::Accounts::AccountModel - + Manual Install Required Instalación manual necesaria - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 Desafortunadamente, la instalación automática de este servicio no está disponible o está desactivada para su plataforma.<br /><br />Por favor use "Instalar desde archivo", obteniéndolo desde su distribución o compilándolo. Más instrucciones aquí:<br /><br />http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_fi.ts b/lang/tomahawk_fi.ts index 4eace57b4c..bdf7b81920 100644 --- a/lang/tomahawk_fi.ts +++ b/lang/tomahawk_fi.ts @@ -369,17 +369,17 @@ yhdistää ja toistaa sinulta virtaa? AudioEngine - + Sorry, Tomahawk couldn't find the track '%1' by %2 Valitettavasti Tomahawk ei löytänyt artistin %2 kappaletta ”%1” - + Sorry, Tomahawk couldn't find the artist '%1' Valitettavasti Tomahawk ei löytänyt artistia ”%1” - + Sorry, Tomahawk couldn't find the album '%1' by %2 Valitettavasti Tomahawk ei löytänyt artistin %2 albumia ”%1” @@ -1355,9 +1355,9 @@ yhdistää ja toistaa sinulta virtaa? QtScriptResolver - - - + + + Script Resolver Warning: API call %1 returned data synchronously. Skriptiselvittimen varoitus: API-kutsu %1 palautti dataa synkronisesti. @@ -1421,7 +1421,7 @@ yhdistää ja toistaa sinulta virtaa? ScriptEngine - + Script Resolver Error: %1 %2 %3 %4 Skriptiselvittimen virhe: %1 %2 %3 %4 @@ -1500,12 +1500,17 @@ yhdistää ja toistaa sinulta virtaa? Asenna selvitin tiedostosta - + + Tomahawk Resolvers (*.axe *.js);;All files (*) + + + + Delete all Access Control entries? Poistetaanko kaikki pääsynvalvontatietueet? - + Do you really want to delete all Access Control entries? You will be asked for a decision again for each peer that you connect to. Haluatko varmasti poistaa kaikki pääsynvalvontatietueet? Sinulta tullaan kysymään päätös uudelleen jokaisen sellaisen vertaisen kohdalla, johon yhdistät. @@ -2078,22 +2083,22 @@ napsauttamalla hiiren oikealla. Poista - + %1 downloads %1 latausta - + Online Verkossa - + Connecting... Yhdistetään... - + Offline Ei verkossa @@ -2101,12 +2106,12 @@ napsauttamalla hiiren oikealla. Tomahawk::Accounts::AccountModel - + Manual Install Required Manuaalinen asennus tarvitaan - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 Valitettavasti tämän selvittimen automaattinen asennus ei ole saatavilla tai on poissa käytöstä alustallasi.<br /><br />Hae selvitin jakelusi kautta tai kääntämällä se itse, ja käytä sitten Asenna tiedostosta -painiketta. Lisäohjeita on osoitteessa:<br /><br />http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_fr.ts b/lang/tomahawk_fr.ts index 588c498161..9558e8e863 100644 --- a/lang/tomahawk_fr.ts +++ b/lang/tomahawk_fr.ts @@ -369,17 +369,17 @@ de se connecter et streamer de vous? AudioEngine - + Sorry, Tomahawk couldn't find the track '%1' by %2 Désolé, on a pas pu trouver la piste '%1' pour %2 - + Sorry, Tomahawk couldn't find the artist '%1' Désolé, on a pas pu trouver l'artiste '%1' - + Sorry, Tomahawk couldn't find the album '%1' by %2 Désolé, on a pas pu trouver l'album '%1' pour %2 @@ -1355,9 +1355,9 @@ de se connecter et streamer de vous? QtScriptResolver - - - + + + Script Resolver Warning: API call %1 returned data synchronously. @@ -1421,7 +1421,7 @@ de se connecter et streamer de vous? ScriptEngine - + Script Resolver Error: %1 %2 %3 %4 Erreur du script de résolution : %1 %2 %3 %4 @@ -1500,12 +1500,17 @@ de se connecter et streamer de vous? Installer un script de résolution depuis un fichier - + + Tomahawk Resolvers (*.axe *.js);;All files (*) + + + + Delete all Access Control entries? Supprimer toutes les entrées de Contrôle d'accès? - + Do you really want to delete all Access Control entries? You will be asked for a decision again for each peer that you connect to. Voulez-vous vraiment supprimer toutes les entrées de contrôle d'accès ? On vous demandera de nouveau votre autorisation pour toutes les nouvelles connexions. @@ -2072,22 +2077,22 @@ de se connecter et streamer de vous? Supprimer - + %1 downloads %1 téléchargements - + Online En Ligne - + Connecting... Connexion en cours... - + Offline Hors ligne @@ -2095,12 +2100,12 @@ de se connecter et streamer de vous? Tomahawk::Accounts::AccountModel - + Manual Install Required Installation manuelle requise - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 Malheureusement, l'installation automatique de ce script de résolution n'est pas disponible ou a été désactivé sur votre plateforme.<br /><br />Utiliser "Installer depuis un fichier" ci-dessus et téléchargez le fichier pour votre distribution, ou compilez-le. D'autres instructions sont disponibles ici :<br /><br />http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_gl.ts b/lang/tomahawk_gl.ts index dd8f99f313..6a9467052d 100644 --- a/lang/tomahawk_gl.ts +++ b/lang/tomahawk_gl.ts @@ -368,17 +368,17 @@ connect and stream from you? AudioEngine - + Sorry, Tomahawk couldn't find the track '%1' by %2 Tomahawk non atopa a pista «%1» de %2 - + Sorry, Tomahawk couldn't find the artist '%1' Tomahawk non atopa o artista «%1» - + Sorry, Tomahawk couldn't find the album '%1' by %2 Tomahawk non atopa o álbum «%1» de %2 @@ -1354,9 +1354,9 @@ connect and stream from you? QtScriptResolver - - - + + + Script Resolver Warning: API call %1 returned data synchronously. @@ -1420,7 +1420,7 @@ connect and stream from you? ScriptEngine - + Script Resolver Error: %1 %2 %3 %4 Erro do solucionador de erros: %1 %2 %3 %4 @@ -1499,12 +1499,17 @@ connect and stream from you? Instalar un resolvedor dende un ficheiro - + + Tomahawk Resolvers (*.axe *.js);;All files (*) + + + + Delete all Access Control entries? Queres borrar tódalas entradas de control de acceso? - + Do you really want to delete all Access Control entries? You will be asked for a decision again for each peer that you connect to. Seguro que queres borrar tódalas entradas de control de acceso? Preguntaráseche de novo para que o confirmes cada vez que te conectes a un parceiro. @@ -2073,22 +2078,22 @@ connect and stream from you? Eliminar - + %1 downloads %1 descargas - + Online Conectado - + Connecting... Conectando... - + Offline Desconectado @@ -2096,12 +2101,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required Precísase facer unha instalación manual - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 Lamentablemente a instalación automática deste resolvedor non está dispoñíbel ou está desactivado para a túa plataforma.<br/><br/>Usa o «instalar dende ficheiro» de arriba, buscándoo para a túa distribución ou compilándoo. Podes atopar máis instrucións aquí:<br/><br/>http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_hi_IN.ts b/lang/tomahawk_hi_IN.ts index 77b7c7d9d5..869b641918 100644 --- a/lang/tomahawk_hi_IN.ts +++ b/lang/tomahawk_hi_IN.ts @@ -368,17 +368,17 @@ connect and stream from you? AudioEngine - + Sorry, Tomahawk couldn't find the track '%1' by %2 - + Sorry, Tomahawk couldn't find the artist '%1' - + Sorry, Tomahawk couldn't find the album '%1' by %2 @@ -1353,9 +1353,9 @@ connect and stream from you? QtScriptResolver - - - + + + Script Resolver Warning: API call %1 returned data synchronously. @@ -1419,7 +1419,7 @@ connect and stream from you? ScriptEngine - + Script Resolver Error: %1 %2 %3 %4 @@ -1498,12 +1498,17 @@ connect and stream from you? - + + Tomahawk Resolvers (*.axe *.js);;All files (*) + + + + Delete all Access Control entries? - + Do you really want to delete all Access Control entries? You will be asked for a decision again for each peer that you connect to. @@ -2070,22 +2075,22 @@ connect and stream from you? - + %1 downloads - + Online - + Connecting... - + Offline @@ -2093,12 +2098,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_hu.ts b/lang/tomahawk_hu.ts index 2d4f1206f4..a411a2c4ab 100644 --- a/lang/tomahawk_hu.ts +++ b/lang/tomahawk_hu.ts @@ -368,17 +368,17 @@ connect and stream from you? AudioEngine - + Sorry, Tomahawk couldn't find the track '%1' by %2 - + Sorry, Tomahawk couldn't find the artist '%1' - + Sorry, Tomahawk couldn't find the album '%1' by %2 @@ -1353,9 +1353,9 @@ connect and stream from you? QtScriptResolver - - - + + + Script Resolver Warning: API call %1 returned data synchronously. @@ -1419,7 +1419,7 @@ connect and stream from you? ScriptEngine - + Script Resolver Error: %1 %2 %3 %4 @@ -1498,12 +1498,17 @@ connect and stream from you? - + + Tomahawk Resolvers (*.axe *.js);;All files (*) + + + + Delete all Access Control entries? - + Do you really want to delete all Access Control entries? You will be asked for a decision again for each peer that you connect to. @@ -2070,22 +2075,22 @@ connect and stream from you? Eltávolítás - + %1 downloads - + Online Elérhető - + Connecting... Csatlakozás... - + Offline Nem elérhető @@ -2093,12 +2098,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_it.ts b/lang/tomahawk_it.ts index 9ced806e79..781ac9f02b 100644 --- a/lang/tomahawk_it.ts +++ b/lang/tomahawk_it.ts @@ -368,17 +368,17 @@ connect and stream from you? AudioEngine - + Sorry, Tomahawk couldn't find the track '%1' by %2 Spiacente, Tomahawk non ha trovato la traccia '%1' di %2 - + Sorry, Tomahawk couldn't find the artist '%1' Spiacente, Tomahawk non ha trovato l'artista '%1' - + Sorry, Tomahawk couldn't find the album '%1' by %2 Spiacente, Tomahawk non ha trovato l'album '%1' di '%2' @@ -1353,9 +1353,9 @@ connect and stream from you? QtScriptResolver - - - + + + Script Resolver Warning: API call %1 returned data synchronously. @@ -1419,7 +1419,7 @@ connect and stream from you? ScriptEngine - + Script Resolver Error: %1 %2 %3 %4 Errore script resolver: %1 %2 %3 %4 @@ -1498,12 +1498,17 @@ connect and stream from you? Installa i resolver da file - + + Tomahawk Resolvers (*.axe *.js);;All files (*) + + + + Delete all Access Control entries? Cancellare tutte le voci di controllo di accesso? - + Do you really want to delete all Access Control entries? You will be asked for a decision again for each peer that you connect to. Vuoi proprio cancellare tutte le voci di controllo accesso? Ti sarà richiesto di decidere ancora tutte le volte che un peer si connetterà con te. @@ -2070,22 +2075,22 @@ connect and stream from you? Rimuovi - + %1 downloads %1 download - + Online In linea - + Connecting... In collegamento... - + Offline Sconnesso @@ -2093,12 +2098,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required Richiesta installazione manuale - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 Sfortunatamente l'installazione automatica di questo resolver non è disponibile o disabilitata per la tua piattaforma.<br /><br />Per favore usa l'opzione "installa da file", scaricandola per la tua distribuzione o compilandola tu stesso. Puoi trovare ulteriori info qui: <br /><br />http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_ja.ts b/lang/tomahawk_ja.ts index 1b5f7da950..691a1dd0db 100644 --- a/lang/tomahawk_ja.ts +++ b/lang/tomahawk_ja.ts @@ -368,17 +368,17 @@ connect and stream from you? AudioEngine - + Sorry, Tomahawk couldn't find the track '%1' by %2 Tomahawkは%2の%1を見つかりませんでした。 - + Sorry, Tomahawk couldn't find the artist '%1' Tomahawkは'%1'と言うアーティストを見つかりませんでした。 - + Sorry, Tomahawk couldn't find the album '%1' by %2 Tomahawkは%2の%1を見つかりませんでした。 @@ -1355,9 +1355,9 @@ connect and stream from you? QtScriptResolver - - - + + + Script Resolver Warning: API call %1 returned data synchronously. @@ -1421,7 +1421,7 @@ connect and stream from you? ScriptEngine - + Script Resolver Error: %1 %2 %3 %4 @@ -1500,12 +1500,17 @@ connect and stream from you? ファイルからリゾルバをインストールする - + + Tomahawk Resolvers (*.axe *.js);;All files (*) + + + + Delete all Access Control entries? 全てのアクセス制御のエントリーを削除しますか? - + Do you really want to delete all Access Control entries? You will be asked for a decision again for each peer that you connect to. 本当に全てのアクセス制御のエントリーを削除しますか?ピア接続に対して、改めて同意を求めます。 @@ -2075,22 +2080,22 @@ connect and stream from you? 削除 - + %1 downloads %1ダウンロード - + Online オンライン - + Connecting... 接続中... - + Offline ・オフライン @@ -2098,12 +2103,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required 手動インストールが要求 - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 残念ながら、このプラットフォームでは、リゾルバの自動インストールは設けてないか、無効にされました。<br /><br />以上の「ファイルからインストール」を使用して、又はディストリビューションから取得するか、自分でコンパイルして下さい。詳しくはこちらを参照:<br /><br />http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_lt.ts b/lang/tomahawk_lt.ts index acfcf7e58d..f3d3de66bd 100644 --- a/lang/tomahawk_lt.ts +++ b/lang/tomahawk_lt.ts @@ -368,17 +368,17 @@ connect and stream from you? AudioEngine - + Sorry, Tomahawk couldn't find the track '%1' by %2 Atsiprašome, Tomahawk nepavyko rasti takelio '%1', atliekamo %2 - + Sorry, Tomahawk couldn't find the artist '%1' Atsiprašome, Tomahawk nepavyko rasti atlikėjo '%1' - + Sorry, Tomahawk couldn't find the album '%1' by %2 Atsiprašome, Tomahawk nepavyko rasti %2 atliekamo albumo '%1' @@ -1353,9 +1353,9 @@ connect and stream from you? QtScriptResolver - - - + + + Script Resolver Warning: API call %1 returned data synchronously. @@ -1419,7 +1419,7 @@ connect and stream from you? ScriptEngine - + Script Resolver Error: %1 %2 %3 %4 @@ -1498,12 +1498,17 @@ connect and stream from you? - + + Tomahawk Resolvers (*.axe *.js);;All files (*) + + + + Delete all Access Control entries? - + Do you really want to delete all Access Control entries? You will be asked for a decision again for each peer that you connect to. @@ -2070,22 +2075,22 @@ connect and stream from you? Pašalinti - + %1 downloads %1 atsisiuntimų - + Online Prisijungęs - + Connecting... Jungiamasi... - + Offline Atsijungęs @@ -2093,12 +2098,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required Reikalingas rankinis įdiegimas - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_pl.ts b/lang/tomahawk_pl.ts index 2f034576e0..a04db894fb 100644 --- a/lang/tomahawk_pl.ts +++ b/lang/tomahawk_pl.ts @@ -369,17 +369,17 @@ połączyć się i strumieniować od ciebie? AudioEngine - + Sorry, Tomahawk couldn't find the track '%1' by %2 Przepraszamy, Tomahawk nie mógł znaleźć utworu '%1' wykonawcy %2 - + Sorry, Tomahawk couldn't find the artist '%1' Przepraszamy, Tomahawk nie mógł znaleźć wykonawcy '%1' - + Sorry, Tomahawk couldn't find the album '%1' by %2 Przepraszamy, Tomahawk nie mógł znaleźć albumu '%1' wykonawcy %2 @@ -1355,9 +1355,9 @@ połączyć się i strumieniować od ciebie? QtScriptResolver - - - + + + Script Resolver Warning: API call %1 returned data synchronously. @@ -1421,7 +1421,7 @@ połączyć się i strumieniować od ciebie? ScriptEngine - + Script Resolver Error: %1 %2 %3 %4 @@ -1500,12 +1500,17 @@ połączyć się i strumieniować od ciebie? Zainstaluj usługę z pliku - + + Tomahawk Resolvers (*.axe *.js);;All files (*) + + + + Delete all Access Control entries? - + Do you really want to delete all Access Control entries? You will be asked for a decision again for each peer that you connect to. @@ -2072,22 +2077,22 @@ połączyć się i strumieniować od ciebie? - + %1 downloads pobrań: %1 - + Online Online - + Connecting... Łączenie... - + Offline Offline @@ -2095,12 +2100,12 @@ połączyć się i strumieniować od ciebie? Tomahawk::Accounts::AccountModel - + Manual Install Required Ręczna instalacja wymagana - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 Niestety, automatyczna instalacja tej usługi jest niedostępna lub wyłączona na twojej platformie.<br /><br />Użyj instalacji z pliku, ściągając usługę lub kompilując ją samodzielnie. Więcej informacji można znaleźć na:<br /><br />http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_pt_BR.ts b/lang/tomahawk_pt_BR.ts index 82a19dad74..37d312d3bb 100644 --- a/lang/tomahawk_pt_BR.ts +++ b/lang/tomahawk_pt_BR.ts @@ -369,17 +369,17 @@ se conecte e faça o stream de você? AudioEngine - + Sorry, Tomahawk couldn't find the track '%1' by %2 Desculpe, o Tomahawk não encontrou a faixa '%1' de %2 - + Sorry, Tomahawk couldn't find the artist '%1' Desculpe, o Tomahawk não encontrou o artista '%1' - + Sorry, Tomahawk couldn't find the album '%1' by %2 Desculpe, o Tomahawk não encontrou o álbum '%1' de %2 @@ -1355,9 +1355,9 @@ se conecte e faça o stream de você? QtScriptResolver - - - + + + Script Resolver Warning: API call %1 returned data synchronously. @@ -1421,7 +1421,7 @@ se conecte e faça o stream de você? ScriptEngine - + Script Resolver Error: %1 %2 %3 %4 @@ -1500,12 +1500,17 @@ se conecte e faça o stream de você? Instalar resolvedor via arquivo - + + Tomahawk Resolvers (*.axe *.js);;All files (*) + + + + Delete all Access Control entries? Excluir todas as entradas de controle de acesso? - + Do you really want to delete all Access Control entries? You will be asked for a decision again for each peer that you connect to. Você realmente quer apagar todas as entradas de controle de acesso? Você será solicitado a tomar uma decisão para cada ponto a que você se conectar. @@ -2072,22 +2077,22 @@ se conecte e faça o stream de você? Remover - + %1 downloads %1 downloads - + Online Online - + Connecting... Conectando... - + Offline Offline @@ -2095,12 +2100,12 @@ se conecte e faça o stream de você? Tomahawk::Accounts::AccountModel - + Manual Install Required Instalação Manual Requerida - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 Infelizmente, a instalação automática deste resolvedor não esta disponível ou esta desabilitada para sua plataforma.<br /><br />Por favor, utilize a opção "Instalar via arquivo" acima e instale do arquivo baixado ou compilado. Instruções adicionais podem ser encontradas aqui:<br /><br />http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_ru.ts b/lang/tomahawk_ru.ts index 077c366c6e..bc03e3afbc 100644 --- a/lang/tomahawk_ru.ts +++ b/lang/tomahawk_ru.ts @@ -372,17 +372,17 @@ connect and stream from you? AudioEngine - + Sorry, Tomahawk couldn't find the track '%1' by %2 К сожалению, Tomahawk не смог найти песню '%1' %2 - + Sorry, Tomahawk couldn't find the artist '%1' К сожалению, Tomahawk не смог найти исполнителя '%1' - + Sorry, Tomahawk couldn't find the album '%1' by %2 К сожалению, Tomahawk не смог найти альбом '%1' %2 @@ -1358,9 +1358,9 @@ connect and stream from you? QtScriptResolver - - - + + + Script Resolver Warning: API call %1 returned data synchronously. @@ -1424,7 +1424,7 @@ connect and stream from you? ScriptEngine - + Script Resolver Error: %1 %2 %3 %4 @@ -1503,12 +1503,17 @@ connect and stream from you? Установить resolver из файла - + + Tomahawk Resolvers (*.axe *.js);;All files (*) + + + + Delete all Access Control entries? Удаление всех записей контроля доступа? - + Do you really want to delete all Access Control entries? You will be asked for a decision again for each peer that you connect to. Вы действительно хотите удалить все записи Access Control? Вас заново спросят о каждом соединении к которым вы были подключены. @@ -2078,22 +2083,22 @@ connect and stream from you? Удалить - + %1 downloads %1 загружено - + Online В сети - + Connecting... Соединяюсь... - + Offline Не в сети @@ -2101,12 +2106,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required Ручная установка обязательно - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 К сожалению, автоматическая установка этого расширения не доступна или недоступна для вашей платформы. <br /> <br /> Пожалуйста, используйте "Установить из файла", по получении его из дистрибутива или скомпилируйте его самостоятельно. Дальнейшие инструкции можно найти здесь: <br /> <br /> http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_sv.ts b/lang/tomahawk_sv.ts index a2f52b99a4..24daaa8fee 100644 --- a/lang/tomahawk_sv.ts +++ b/lang/tomahawk_sv.ts @@ -369,17 +369,17 @@ ansluta och strömma från dig? AudioEngine - + Sorry, Tomahawk couldn't find the track '%1' by %2 Tyvärr! Tomahawk kunde inte hitta spåret '%1' av %2 - + Sorry, Tomahawk couldn't find the artist '%1' Tyvärr! Tomahawk kunde inte hitta artisten '%1' - + Sorry, Tomahawk couldn't find the album '%1' by %2 Tyvärr! Tomahawk kunde inte hitta albumet '%1' av %2 @@ -1355,9 +1355,9 @@ ansluta och strömma från dig? QtScriptResolver - - - + + + Script Resolver Warning: API call %1 returned data synchronously. Skript Resolver-varning: API-anrop %1 returnerade data synkront @@ -1421,7 +1421,7 @@ ansluta och strömma från dig? ScriptEngine - + Script Resolver Error: %1 %2 %3 %4 Skriptfel i resolvern: %1 %2 %3 %4 @@ -1500,12 +1500,17 @@ ansluta och strömma från dig? Installera resolver från fil - + + Tomahawk Resolvers (*.axe *.js);;All files (*) + Tomahawk Resolvers (*.axe *.js);;Alla filer (*) + + + Delete all Access Control entries? Ta bort alla åtkomstkontrollsposter - + Do you really want to delete all Access Control entries? You will be asked for a decision again for each peer that you connect to. Vill du verkligen ta bort alla åtkomstkontrollsposter? Du kommer att bli förfrågad igen för varje nod du försöker ansluta till. @@ -2074,22 +2079,22 @@ och radiostationer baserat på din personliga profil Ta bort - + %1 downloads %1 nedladdningar - + Online Uppkopplad - + Connecting... Ansluter… - + Offline Nedkopplad @@ -2097,12 +2102,12 @@ och radiostationer baserat på din personliga profil Tomahawk::Accounts::AccountModel - + Manual Install Required Manuell installation krävs - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 Tyvärr är inte den automatiska installationen av denna resolvern tillgänglig eller så är den inte tillgänglig för din plattform<br /><br />Var god och använd "Installera från fil" ovan genom att hämta den från din distribution, eller genom att kompilera den själv. Fler instruktioner går att finnas här:<br /> <br />http://www.tomahawk-player.org/resolvers/%1 @@ -3670,7 +3675,7 @@ anger du PIN-koden här: Sorry, your filter '%1' did not match any results. - Entschuldige, dein Filter '%1' erzeugte keine Ergebnisse. + Tyvärr, ditt filter '%1' gav inga träffar @@ -3709,7 +3714,7 @@ anger du PIN-koden här: Sorry, your filter '%1' did not match any results. - Tyvärr! Dina filter '%1' matchade inga resultat + Tyvärr! Ditt filter '%1' gav inga träffar @@ -3722,7 +3727,7 @@ anger du PIN-koden här: The Twitter plugin allows you to discover and play music from your Twitter friends running Tomahawk and post messages to your account. - Twitter-pluginnet låter dig utforska och spela musik från dina Twitter-vänner som använder Tomahawk, samt posta meddelanden till ditt konto + Twitter-pluginnet låter dig utforska och spela musik från dina Twitter-vänner som använder Tomahawk, samt posta tweets till ditt konto @@ -3748,7 +3753,7 @@ If you want to connect Tomahawk to your friends using Twitter, select the type o You can re-send a sync message at any time simply by sending another tweet using the button. -Om du bara vill posta ett tweet så är du färdig. +Vill posta ett tweet, är du färdig. Om du vill ansluta Tomahawk till dina vänner med Twitter så välj vilken typ av tweet och tryck på knappen nedan för att skicka ett synkat meddelande. Båda måste följa varandra då direktmeddelanden används. Var sedan (väldigt) tålmodig då det kan ta flera minuter! @@ -3831,12 +3836,12 @@ Du kan skicka om ett synkat meddelande när som helst genom att skicka ett tweet Recent Additions - Senaste tillägg + Senast tillagda Newest Stations & Playlists - Nyaste stationer och spellistor + Nyaste stationer & spellistor @@ -3846,7 +3851,7 @@ Du kan skicka om ett synkat meddelande när som helst genom att skicka ett tweet Recently played tracks - Senast uppspelade spår + Nyligen spelade spår diff --git a/lang/tomahawk_tr.ts b/lang/tomahawk_tr.ts index 84e6401fb5..d475239650 100644 --- a/lang/tomahawk_tr.ts +++ b/lang/tomahawk_tr.ts @@ -368,17 +368,17 @@ connect and stream from you? AudioEngine - + Sorry, Tomahawk couldn't find the track '%1' by %2 - + Sorry, Tomahawk couldn't find the artist '%1' - + Sorry, Tomahawk couldn't find the album '%1' by %2 @@ -1353,9 +1353,9 @@ connect and stream from you? QtScriptResolver - - - + + + Script Resolver Warning: API call %1 returned data synchronously. @@ -1419,7 +1419,7 @@ connect and stream from you? ScriptEngine - + Script Resolver Error: %1 %2 %3 %4 @@ -1498,12 +1498,17 @@ connect and stream from you? - + + Tomahawk Resolvers (*.axe *.js);;All files (*) + + + + Delete all Access Control entries? - + Do you really want to delete all Access Control entries? You will be asked for a decision again for each peer that you connect to. @@ -2070,22 +2075,22 @@ connect and stream from you? - + %1 downloads - + Online - + Connecting... - + Offline @@ -2093,12 +2098,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_zh_CN.ts b/lang/tomahawk_zh_CN.ts index d0f0b74dce..6e465a83ab 100644 --- a/lang/tomahawk_zh_CN.ts +++ b/lang/tomahawk_zh_CN.ts @@ -368,17 +368,17 @@ connect and stream from you? AudioEngine - + Sorry, Tomahawk couldn't find the track '%1' by %2 抱歉,Tomahawk 未找到 %2 的歌曲 '%1' - + Sorry, Tomahawk couldn't find the artist '%1' 抱歉,Tomahawk 无法找到艺术家 '%1' - + Sorry, Tomahawk couldn't find the album '%1' by %2 抱歉,Tomahawk 无法找到 %2 的专辑 '%1' @@ -1354,9 +1354,9 @@ connect and stream from you? QtScriptResolver - - - + + + Script Resolver Warning: API call %1 returned data synchronously. @@ -1420,7 +1420,7 @@ connect and stream from you? ScriptEngine - + Script Resolver Error: %1 %2 %3 %4 @@ -1499,12 +1499,17 @@ connect and stream from you? 从文件安装解析器 - + + Tomahawk Resolvers (*.axe *.js);;All files (*) + + + + Delete all Access Control entries? 删除所有的访问控制项? - + Do you really want to delete all Access Control entries? You will be asked for a decision again for each peer that you connect to. 你真的想删除所有的访问控制项吗?将在对每个连接的客户端操作后再次询问。 @@ -2073,22 +2078,22 @@ connect and stream from you? 移除 - + %1 downloads %1 个下载 - + Online 在线 - + Connecting... 连接中... - + Offline 离线 @@ -2096,12 +2101,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required 手动安装需求组件 - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 抱歉,这个解析器的自动安装功能在当前平台上不可用或已被禁用。<br /><br />请使用上面的 "从文件安装" 选项,然后手动选择文件安装。更详细的指导可以参见这里:<br /><br />http://www.tomahawk-player.org/resolvers/%1 diff --git a/lang/tomahawk_zh_TW.ts b/lang/tomahawk_zh_TW.ts index c2a6add397..9b3196d593 100644 --- a/lang/tomahawk_zh_TW.ts +++ b/lang/tomahawk_zh_TW.ts @@ -368,17 +368,17 @@ connect and stream from you? AudioEngine - + Sorry, Tomahawk couldn't find the track '%1' by %2 - + Sorry, Tomahawk couldn't find the artist '%1' - + Sorry, Tomahawk couldn't find the album '%1' by %2 @@ -1353,9 +1353,9 @@ connect and stream from you? QtScriptResolver - - - + + + Script Resolver Warning: API call %1 returned data synchronously. @@ -1419,7 +1419,7 @@ connect and stream from you? ScriptEngine - + Script Resolver Error: %1 %2 %3 %4 @@ -1498,12 +1498,17 @@ connect and stream from you? 從檔案安裝解析器 - + + Tomahawk Resolvers (*.axe *.js);;All files (*) + + + + Delete all Access Control entries? - + Do you really want to delete all Access Control entries? You will be asked for a decision again for each peer that you connect to. @@ -2070,22 +2075,22 @@ connect and stream from you? - + %1 downloads - + Online 線上 - + Connecting... 連接中... - + Offline 離線 @@ -2093,12 +2098,12 @@ connect and stream from you? Tomahawk::Accounts::AccountModel - + Manual Install Required - + Unfortunately, automatic installation of this resolver is not available or disabled for your platform.<br /><br />Please use "Install from file" above, by fetching it from your distribution or compiling it yourself. Further instructions can be found here:<br /><br />http://www.tomahawk-player.org/resolvers/%1 From 9f79163e53aeda87495844f033eb69c6df9bd074 Mon Sep 17 00:00:00 2001 From: "Uwe L. Korn" Date: Sun, 24 Mar 2013 02:35:46 +0100 Subject: [PATCH 65/76] Add a 'Add to Playlist' entry to the ContextMenu --- src/libtomahawk/ContextMenu.cpp | 28 +++++++++++++++++++++++++++- src/libtomahawk/ContextMenu.h | 6 +++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/ContextMenu.cpp b/src/libtomahawk/ContextMenu.cpp index c67a63c51e..668426cec1 100644 --- a/src/libtomahawk/ContextMenu.cpp +++ b/src/libtomahawk/ContextMenu.cpp @@ -27,6 +27,7 @@ #include "Result.h" #include "collection/Collection.h" #include "Source.h" +#include "SourceList.h" #include "Artist.h" #include "Album.h" @@ -43,7 +44,7 @@ ContextMenu::ContextMenu( QWidget* parent ) m_sigmap = new QSignalMapper( this ); connect( m_sigmap, SIGNAL( mapped( int ) ), SLOT( onTriggered( int ) ) ); - m_supportedActions = ActionPlay | ActionQueue | ActionCopyLink | ActionLove | ActionStopAfter | ActionPage | ActionEditMetadata; + m_supportedActions = ActionPlay | ActionQueue | ActionPlaylist | ActionCopyLink | ActionLove | ActionStopAfter | ActionPage | ActionEditMetadata; } @@ -70,6 +71,14 @@ ContextMenu::itemCount() const } +void +ContextMenu::addToPlaylist( int playlistIdx ) +{ + Tomahawk::playlist_ptr playlist = m_playlists.at( playlistIdx ); + playlist->addEntries( m_queries, playlist->currentrevision() ); +} + + void ContextMenu::setQueries( const QList& queries ) { @@ -86,6 +95,23 @@ ContextMenu::setQueries( const QList& queries ) if ( m_supportedActions & ActionQueue ) m_sigmap->setMapping( addAction( tr( "Add to &Queue" ) ), ActionQueue ); + if ( m_supportedActions & ActionPlaylist ) { + // Get the current list of all playlists. + m_playlists = SourceList::instance()->getLocal()->dbCollection()->playlists(); + m_playlists_sigmap = new QSignalMapper( this ); + + // Build the menu listing all available playlists + QMenu* playlistMenu = addMenu( tr( "Add to &Playlist" ) ); + for ( int i = 0; i < m_playlists.length(); ++i ) + { + QAction* action = new QAction( m_playlists.at(i)->title() , this ); + playlistMenu->addAction(action); + m_playlists_sigmap->setMapping( action, i ); + connect( action, SIGNAL( triggered() ), m_playlists_sigmap, SLOT( map() )); + } + connect( m_playlists_sigmap, SIGNAL( mapped( int ) ), this, SLOT( addToPlaylist( int ) ) ); + } + if ( m_supportedActions & ActionStopAfter && itemCount() == 1 ) { if ( AudioEngine::instance()->stopAfterTrack() == queries.first() ) diff --git a/src/libtomahawk/ContextMenu.h b/src/libtomahawk/ContextMenu.h index 6844f04ee8..19484669df 100644 --- a/src/libtomahawk/ContextMenu.h +++ b/src/libtomahawk/ContextMenu.h @@ -46,7 +46,8 @@ Q_OBJECT ActionTrackPage = 65, ActionArtistPage = 66, ActionAlbumPage = 67, - ActionEditMetadata = 128 + ActionEditMetadata = 128, + ActionPlaylist = 256 }; explicit ContextMenu( QWidget* parent = 0 ); @@ -78,15 +79,18 @@ private slots: void copyLink(); void openPage( MenuActions action ); void addToQueue(); + void addToPlaylist( int playlistIdx ); void onSocialActionsLoaded(); private: QSignalMapper* m_sigmap; + QSignalMapper* m_playlists_sigmap; int m_supportedActions; QAction* m_loveAction; + QList< Tomahawk::playlist_ptr > m_playlists; QList< Tomahawk::query_ptr > m_queries; QList< Tomahawk::artist_ptr > m_artists; QList< Tomahawk::album_ptr > m_albums; From 72d36b9bfc6f134f141ecc30f7a18cee2915ec60 Mon Sep 17 00:00:00 2001 From: "Uwe L. Korn" Date: Sun, 24 Mar 2013 02:43:29 +0100 Subject: [PATCH 66/76] Include --verbose in --help --- src/TomahawkApp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/TomahawkApp.cpp b/src/TomahawkApp.cpp index 252108f026..fc4f5689e2 100644 --- a/src/TomahawkApp.cpp +++ b/src/TomahawkApp.cpp @@ -397,6 +397,7 @@ TomahawkApp::printHelp() echo( " --testdb Use a test database instead of real collection" ); echo( " --noupnp Disable UPnP" ); echo( " --nosip Disable SIP" ); + echo( " --verbose Increase verbosity (activates debug output)" ); echo(); echo( "Playback Controls:" ); echo( " --play Start/resume playback" ); From f59cfe5894439cd66893b99ad6a6471cf2f26895 Mon Sep 17 00:00:00 2001 From: "Uwe L. Korn" Date: Sun, 24 Mar 2013 03:13:17 +0100 Subject: [PATCH 67/76] Escape ampersands in menu entry strings * Fixes TWK-1172 --- src/libtomahawk/ContextMenu.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/libtomahawk/ContextMenu.cpp b/src/libtomahawk/ContextMenu.cpp index 668426cec1..c93001ed03 100644 --- a/src/libtomahawk/ContextMenu.cpp +++ b/src/libtomahawk/ContextMenu.cpp @@ -135,13 +135,18 @@ ContextMenu::setQueries( const QList& queries ) if ( m_supportedActions & ActionPage && itemCount() == 1 ) { + // Ampersands need to be escaped as they indicate a keyboard shortcut + QString track = m_queries.first()->track().replace( QString( "&" ), QString( "&&" ) ); m_sigmap->setMapping( addAction( ImageRegistry::instance()->icon( RESPATH "images/track-icon.svg" ), - tr( "&Go to \"%1\"" ).arg( m_queries.first()->track() ) ), ActionTrackPage ); - if ( !m_queries.first()->album().isEmpty() ) + tr( "&Go to \"%1\"" ).arg( track ) ), ActionTrackPage ); + if ( !m_queries.first()->album().isEmpty() ) { + QString album = m_queries.first()->album().replace( QString( "&" ), QString( "&&" ) ); m_sigmap->setMapping( addAction( ImageRegistry::instance()->icon( RESPATH "images/album-icon.svg" ), - tr( "Go to \"%1\"" ).arg( m_queries.first()->album() ) ), ActionAlbumPage ); + tr( "Go to \"%1\"" ).arg( album ) ), ActionAlbumPage ); + } + QString artist = m_queries.first()->artist().replace( QString( "&" ), QString( "&&" ) ); m_sigmap->setMapping( addAction( ImageRegistry::instance()->icon( RESPATH "images/artist-icon.svg" ), - tr( "Go to \"%1\"" ).arg( m_queries.first()->artist() ) ), ActionArtistPage ); + tr( "Go to \"%1\"" ).arg( artist ) ), ActionArtistPage ); } addSeparator(); From e1e12edc874d374fa87d70689749d6640dc10619 Mon Sep 17 00:00:00 2001 From: "Uwe L. Korn" Date: Sun, 24 Mar 2013 03:23:28 +0100 Subject: [PATCH 68/76] Add ampersand escaping for Albums and Artists --- src/libtomahawk/ContextMenu.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/libtomahawk/ContextMenu.cpp b/src/libtomahawk/ContextMenu.cpp index c93001ed03..ed15bb0a25 100644 --- a/src/libtomahawk/ContextMenu.cpp +++ b/src/libtomahawk/ContextMenu.cpp @@ -136,15 +136,15 @@ ContextMenu::setQueries( const QList& queries ) if ( m_supportedActions & ActionPage && itemCount() == 1 ) { // Ampersands need to be escaped as they indicate a keyboard shortcut - QString track = m_queries.first()->track().replace( QString( "&" ), QString( "&&" ) ); + const QString track = m_queries.first()->track().replace( QString( "&" ), QString( "&&" ) ); m_sigmap->setMapping( addAction( ImageRegistry::instance()->icon( RESPATH "images/track-icon.svg" ), tr( "&Go to \"%1\"" ).arg( track ) ), ActionTrackPage ); if ( !m_queries.first()->album().isEmpty() ) { - QString album = m_queries.first()->album().replace( QString( "&" ), QString( "&&" ) ); + const QString album = m_queries.first()->album().replace( QString( "&" ), QString( "&&" ) ); m_sigmap->setMapping( addAction( ImageRegistry::instance()->icon( RESPATH "images/album-icon.svg" ), tr( "Go to \"%1\"" ).arg( album ) ), ActionAlbumPage ); } - QString artist = m_queries.first()->artist().replace( QString( "&" ), QString( "&&" ) ); + const QString artist = m_queries.first()->artist().replace( QString( "&" ), QString( "&&" ) ); m_sigmap->setMapping( addAction( ImageRegistry::instance()->icon( RESPATH "images/artist-icon.svg" ), tr( "Go to \"%1\"" ).arg( artist ) ), ActionArtistPage ); } @@ -198,10 +198,12 @@ ContextMenu::setAlbums( const QList& albums ) if ( m_supportedActions & ActionPage && itemCount() == 1 ) { + const QString album = m_albums.first()->name().replace( QString( "&" ), QString( "&&" ) ); m_sigmap->setMapping( addAction( ImageRegistry::instance()->icon( RESPATH "images/album-icon.svg" ), - tr( "&Go to \"%1\"" ).arg( m_albums.first()->name() ) ), ActionAlbumPage ); + tr( "&Go to \"%1\"" ).arg( album ) ), ActionAlbumPage ); + const QString artist = m_albums.first()->artist()->name().replace( QString( "&" ), QString( "&&" ) ); m_sigmap->setMapping( addAction( ImageRegistry::instance()->icon( RESPATH "images/artist-icon.svg" ), - tr( "Go to \"%1\"" ).arg( m_albums.first()->artist()->name() ) ), ActionArtistPage ); + tr( "Go to \"%1\"" ).arg( artist ) ), ActionArtistPage ); } //m_sigmap->setMapping( addAction( tr( "&Add to Playlist" ) ), ActionAddToPlaylist ); @@ -245,9 +247,11 @@ ContextMenu::setArtists( const QList& artists ) addSeparator(); - if ( m_supportedActions & ActionPage && itemCount() == 1 ) + if ( m_supportedActions & ActionPage && itemCount() == 1 ) { + const QString artist = m_artists.first()->name().replace( QString( "&" ), QString( "&&" ) ); m_sigmap->setMapping( addAction( ImageRegistry::instance()->icon( RESPATH "images/artist-icon.svg" ), - tr( "&Go to \"%1\"" ).arg( m_artists.first()->name() ) ), ActionArtistPage ); + tr( "&Go to \"%1\"" ).arg( artist ) ), ActionArtistPage ); + } //m_sigmap->setMapping( addAction( tr( "&Add to Playlist" ) ), ActionAddToPlaylist ); From bb31fa1ca75dedc08f767d7b9bef7d6dc4b8000c Mon Sep 17 00:00:00 2001 From: loclamor Date: Thu, 28 Mar 2013 15:15:38 +0100 Subject: [PATCH 69/76] use TomahawkUtils::nam() instead create another qNetworkAccessManager --- src/libtomahawk/resolvers/QtScriptResolver.cpp | 3 +-- src/libtomahawk/resolvers/QtScriptResolver.h | 1 - src/libtomahawk/utils/CloudStream.cpp | 3 +-- src/libtomahawk/utils/CloudStream.h | 1 - 4 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/libtomahawk/resolvers/QtScriptResolver.cpp b/src/libtomahawk/resolvers/QtScriptResolver.cpp index add0cc903d..8a6f8848c6 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.cpp +++ b/src/libtomahawk/resolvers/QtScriptResolver.cpp @@ -98,7 +98,6 @@ QtScriptResolverHelper::QtScriptResolverHelper( const QString& scriptPath, QtScr { m_scriptPath = scriptPath; m_resolver = parent; - network = new QNetworkAccessManager(this); } @@ -392,7 +391,7 @@ QtScriptResolverHelper::readCloudFile(const QString& fileName, const QString& fi CloudStream* stream = new CloudStream( download_url, fileName, fileId, - size, headers, network, m_resolver, + size, headers, m_resolver, javascriptRefreshUrlFunction, refreshUrlEachTime ); stream->Precache(); boost::scoped_ptr tag; diff --git a/src/libtomahawk/resolvers/QtScriptResolver.h b/src/libtomahawk/resolvers/QtScriptResolver.h index 2ad3530365..5d25a81ca1 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.h +++ b/src/libtomahawk/resolvers/QtScriptResolver.h @@ -104,7 +104,6 @@ public slots: #ifdef QCA2_FOUND QCA::Initializer m_qcaInit; #endif - QNetworkAccessManager* network; }; class DLLEXPORT ScriptEngine : public QWebPage diff --git a/src/libtomahawk/utils/CloudStream.cpp b/src/libtomahawk/utils/CloudStream.cpp index 16122e4ee6..10f31660b7 100644 --- a/src/libtomahawk/utils/CloudStream.cpp +++ b/src/libtomahawk/utils/CloudStream.cpp @@ -44,7 +44,6 @@ CloudStream::CloudStream( QUrl& url, const QString& fileId, const long length, QVariantMap& headers, - QNetworkAccessManager* network, QtScriptResolver* scriptResolver, const QString & javascriptRefreshUrlFunction, const bool refreshUrlEachTime ) @@ -55,7 +54,6 @@ CloudStream::CloudStream( QUrl& url, , m_length( length ) , m_headers( headers ) , m_cursor( 0 ) - , m_network( network ) , m_cache( length ) , m_num_requests( 0 ) , m_num_requests_in_error( 0 ) @@ -63,6 +61,7 @@ CloudStream::CloudStream( QUrl& url, , m_javascriptRefreshUrlFunction( javascriptRefreshUrlFunction ) , m_refreshUrlEachTime( refreshUrlEachTime ) { + m_network = TomahawkUtils::nam(); tDebug( LOGINFO ) << "#### Cloudstream : CloudStream object created for " << m_filename << " : " << m_url.toString(); } diff --git a/src/libtomahawk/utils/CloudStream.h b/src/libtomahawk/utils/CloudStream.h index 57ae132b9b..effcc73cdd 100644 --- a/src/libtomahawk/utils/CloudStream.h +++ b/src/libtomahawk/utils/CloudStream.h @@ -39,7 +39,6 @@ class CloudStream : public QObject, public TagLib::IOStream const QString& fileId, const long length, QVariantMap& headers, - QNetworkAccessManager* network, QtScriptResolver *scriptResolver, const QString& javascriptRefreshUrlFunction, const bool refreshUrlEachTime ); From 597203ff4b7e903c26f36b2d69c7b88de7844b88 Mon Sep 17 00:00:00 2001 From: loclamor Date: Thu, 28 Mar 2013 16:24:22 +0100 Subject: [PATCH 70/76] correction of conflict resolution error --- src/libtomahawk/resolvers/QtScriptResolver.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/libtomahawk/resolvers/QtScriptResolver.h b/src/libtomahawk/resolvers/QtScriptResolver.h index 16ce1b9b3a..bcdce7da54 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.h +++ b/src/libtomahawk/resolvers/QtScriptResolver.h @@ -79,9 +79,6 @@ Q_OBJECT void customIODeviceFactory( const Tomahawk::result_ptr& result, boost::function< void( QSharedPointer< QIODevice >& ) > callback ); // async - void customIODeviceFactory( const Tomahawk::result_ptr& result, - boost::function< void( QSharedPointer< QIODevice >& ) > callback ); // async - public slots: QByteArray readRaw( const QString& fileName ); QString readBase64( const QString& fileName ); From 264eb4b0add5df76278fe256aeed5ebb9c420f6e Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Thu, 28 Mar 2013 18:53:07 +0100 Subject: [PATCH 71/76] Add header in asynchronous and synchronous custom url handler. --- .../resolvers/QtScriptResolver.cpp | 28 ++++++++++--------- src/libtomahawk/resolvers/QtScriptResolver.h | 6 ++-- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/libtomahawk/resolvers/QtScriptResolver.cpp b/src/libtomahawk/resolvers/QtScriptResolver.cpp index 4b52ff9aa2..567d16ba65 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.cpp +++ b/src/libtomahawk/resolvers/QtScriptResolver.cpp @@ -531,7 +531,7 @@ QtScriptResolverHelper::customIODeviceFactory( const Tomahawk::result_ptr& resul .arg( origResultUrl ); QString urlStr; - QNetworkRequest req; + QVariantMap headers; QVariant jsResult = m_resolver->m_engine->mainFrame()->evaluateJavaScript( getUrl ); if ( jsResult.type() == QVariant::String ) @@ -544,36 +544,32 @@ QtScriptResolverHelper::customIODeviceFactory( const Tomahawk::result_ptr& resul urlStr = request["url"].toString(); - QVariantMap headers = request["headers"].toMap(); - foreach ( const QString& headerName, headers.keys() ) - { - req.setRawHeader( headerName.toLocal8Bit(), headers[headerName].toString().toLocal8Bit() ); - } + headers = request["headers"].toMap(); } - QUrl url = QUrl::fromEncoded( urlStr.toUtf8() ); - req.setUrl( url ); - - returnStreamUrl( urlStr, callback ); + returnStreamUrl( urlStr, callback, headers ); } } void QtScriptResolverHelper::reportStreamUrl( const QString& qid, - const QString& streamUrl ) + const QString& streamUrl, + const QVariantMap& headers ) { if ( !m_streamCallbacks.contains( qid ) ) return; boost::function< void( QSharedPointer< QIODevice >& ) > callback = m_streamCallbacks.take( qid ); - returnStreamUrl( streamUrl, callback ); + returnStreamUrl( streamUrl, callback, headers ); } void -QtScriptResolverHelper::returnStreamUrl( const QString& streamUrl, boost::function< void( QSharedPointer< QIODevice >& ) > callback ) +QtScriptResolverHelper::returnStreamUrl( const QString& streamUrl, + boost::function< void( QSharedPointer< QIODevice >& ) > callback, + const QVariantMap& headers) { QSharedPointer< QIODevice > sp; if ( streamUrl.isEmpty() ) @@ -584,6 +580,12 @@ QtScriptResolverHelper::returnStreamUrl( const QString& streamUrl, boost::functi QUrl url = QUrl::fromEncoded( streamUrl.toUtf8() ); QNetworkRequest req( url ); + + foreach ( const QString& headerName, headers.keys() ) + { + req.setRawHeader( headerName.toLocal8Bit(), headers[headerName].toString().toLocal8Bit() ); + } + tDebug() << "Creating a QNetowrkReply with url:" << req.url().toString(); QNetworkReply* reply = TomahawkUtils::nam()->get( req ); diff --git a/src/libtomahawk/resolvers/QtScriptResolver.h b/src/libtomahawk/resolvers/QtScriptResolver.h index bcdce7da54..c8f56eaebb 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.h +++ b/src/libtomahawk/resolvers/QtScriptResolver.h @@ -60,7 +60,7 @@ Q_OBJECT Q_INVOKABLE QString md5( const QByteArray& input ); Q_INVOKABLE void addCustomUrlHandler( const QString& protocol, const QString& callbackFuncName, const QString& isAsynchronous = "false" ); - Q_INVOKABLE void reportStreamUrl( const QString& qid, const QString& streamUrl ); + Q_INVOKABLE void reportStreamUrl( const QString& qid, const QString& streamUrl, const QVariantMap& headers = QVariantMap() ); Q_INVOKABLE QByteArray base64Encode( const QByteArray& input ); Q_INVOKABLE QByteArray base64Decode( const QByteArray& input ); @@ -99,7 +99,9 @@ public slots: void reportCapabilities( const QVariant& capabilities ); private: - void returnStreamUrl( const QString& streamUrl, boost::function< void( QSharedPointer< QIODevice >& ) > callback ); + void returnStreamUrl( const QString& streamUrl, + boost::function< void( QSharedPointer< QIODevice >& ) > callback , + const QVariantMap &headers = QVariantMap() ); QString m_scriptPath, m_urlCallback; QHash< QString, boost::function< void( QSharedPointer< QIODevice >& ) > > m_streamCallbacks; bool m_urlCallbackIsAsync; From 1c5aa22fcda94873979cd3b3e1bc3c96729d0654 Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Fri, 29 Mar 2013 03:54:05 +0100 Subject: [PATCH 72/76] Parse ID3 tags Asynchronously. --- .../resolvers/QtScriptResolver.cpp | 114 +--------- src/libtomahawk/resolvers/QtScriptResolver.h | 3 + src/libtomahawk/utils/CloudStream.cpp | 204 ++++++++++++++---- src/libtomahawk/utils/CloudStream.h | 26 ++- 4 files changed, 200 insertions(+), 147 deletions(-) diff --git a/src/libtomahawk/resolvers/QtScriptResolver.cpp b/src/libtomahawk/resolvers/QtScriptResolver.cpp index 567d16ba65..37c0f3839e 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.cpp +++ b/src/libtomahawk/resolvers/QtScriptResolver.cpp @@ -27,7 +27,7 @@ #include "ScriptCollection.h" #include "SourceList.h" - +#include "utils/CloudStream.h" #include "utils/TomahawkUtils.h" #include "TomahawkSettings.h" @@ -57,35 +57,6 @@ #include -//--- includes readcloudFile -#include "utils/CloudStream.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef TAGLIB_HAS_OPUS -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "qjson/serializer.h" -//--- end includes readcloudfile - // FIXME: bloody hack, remove this for 0.3 // this one adds new functionality to old resolvers #define RESOLVER_LEGACY_CODE "var resolver = Tomahawk.resolver.instance ? Tomahawk.resolver.instance : TomahawkResolver;" @@ -369,12 +340,9 @@ QtScriptResolverHelper::readCloudFile(const QString& fileName, const QString& fi QVariantMap request; QUrl download_url; QVariantMap headers; - QVariantMap m; long size = sizeS.toLong(); - QString urlString; - if ( requestJS.type() == QVariant::Map ) { request = requestJS.toMap(); @@ -393,84 +361,22 @@ QtScriptResolverHelper::readCloudFile(const QString& fileName, const QString& fi tDebug( LOGINFO ) << "#### ReadCloudFile : Loading tags of " << fileName << " from " << download_url.toString() << " which have id " << fileId; - m["fileId"] = fileId; - m["mimetype"] = mime_type.toUtf8(); - - CloudStream* stream = new CloudStream( download_url, fileName, fileId, - size, headers, m_resolver, - javascriptRefreshUrlFunction, refreshUrlEachTime ); - stream->Precache(); - boost::scoped_ptr tag; - if ( mime_type == "audio/mpeg" ) // && title.endsWith(".mp3")) - { - tag.reset(new TagLib::MPEG::File( - stream, // Takes ownership. - TagLib::ID3v2::FrameFactory::instance(), - TagLib::AudioProperties::Accurate)); - } - else if ( mime_type == "audio/mp4" || ( mime_type == "audio/mpeg" ) ) // && title.endsWith(".m4a"))) - { - tag.reset( new TagLib::MP4::File( stream, true, TagLib::AudioProperties::Accurate ) ); - } - else if ( mime_type == "application/ogg" || mime_type == "audio/ogg" ) - { - tag.reset( new TagLib::Ogg::Vorbis::File( stream, true, TagLib::AudioProperties::Accurate ) ); - } -#ifdef TAGLIB_HAS_OPUS - else if ( mime_type == "application/opus" || mime_type == "audio/opus" ) - { - tag.reset( new TagLib::Ogg::Opus::File( stream, true, TagLib::AudioProperties::Accurate ) ); - } -#endif - else if ( mime_type == "application/x-flac" || mime_type == "audio/flac" ) - { - tag.reset( new TagLib::FLAC::File( stream, TagLib::ID3v2::FrameFactory::instance(), true, - TagLib::AudioProperties::Accurate ) ); - } - else if ( mime_type == "audio/x-ms-wma" ) - { - tag.reset( new TagLib::ASF::File( stream, true, TagLib::AudioProperties::Accurate ) ); - } - else - { - tDebug( LOGINFO ) << "Unknown mime type for tagging:" << mime_type; - } + size, mime_type, headers, m_resolver, + javascriptRefreshUrlFunction, javascriptCallbackFunction, refreshUrlEachTime ); - if (stream->num_requests() > 2) { - // Warn if pre-caching failed. - tDebug( LOGINFO ) << "Total requests for file:" << fileName - << " : " << stream->num_requests() << " with " - << stream->cached_bytes() << " bytes cached"; - } + connect( stream, SIGNAL( tagsReady(QVariantMap &, const QString& ) ), this, SLOT( onTagReady( QVariantMap&, const QString& ) ) ); + stream->precache(); +} - //construction of the tag's map - if ( tag->tag() && !tag->tag()->isEmpty() ) - { - m["track"] = tag->tag()->title().toCString( true ); - m["artist"] = tag->tag()->artist().toCString( true ); - m["album"] = tag->tag()->album().toCString( true ); - m["size"] = QString::number( size ); - if ( tag->tag()->track() != 0 ) - { - m["albumpos"] = tag->tag()->track(); - } - if ( tag->tag()->year() != 0 ) - { - m["year"] = tag->tag()->year(); - } - - if ( tag->audioProperties() ) - { - m["duration"] = tag->audioProperties()->length(); - m["bitrate"] = tag->audioProperties()->bitrate(); - } - } +void +QtScriptResolverHelper::onTagReady( QVariantMap &tags, const QString& javascriptCallbackFunction ) +{ QJson::Serializer serializer; - QByteArray json = serializer.serialize( m ); + QByteArray json = serializer.serialize( tags ); tDebug() << "#### ReadCloudFile : Sending tags to js : " << json; diff --git a/src/libtomahawk/resolvers/QtScriptResolver.h b/src/libtomahawk/resolvers/QtScriptResolver.h index c8f56eaebb..6b991b9d70 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.h +++ b/src/libtomahawk/resolvers/QtScriptResolver.h @@ -98,6 +98,9 @@ public slots: void reportCapabilities( const QVariant& capabilities ); +private slots: + void onTagReady(QVariantMap &tags, const QString&); + private: void returnStreamUrl( const QString& streamUrl, boost::function< void( QSharedPointer< QIODevice >& ) > callback , diff --git a/src/libtomahawk/utils/CloudStream.cpp b/src/libtomahawk/utils/CloudStream.cpp index 10f31660b7..2134f2ed96 100644 --- a/src/libtomahawk/utils/CloudStream.cpp +++ b/src/libtomahawk/utils/CloudStream.cpp @@ -23,9 +23,35 @@ #include #include #include +#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef TAGLIB_HAS_OPUS +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "qjson/serializer.h" #include "utils/Logger.h" @@ -43,9 +69,11 @@ CloudStream::CloudStream( QUrl& url, const QString& filename, const QString& fileId, const long length, + const QString& mimeType, QVariantMap& headers, QtScriptResolver* scriptResolver, const QString & javascriptRefreshUrlFunction, + const QString& javascriptCallbackFunction, const bool refreshUrlEachTime ) : m_url( url ) , m_filename( filename ) @@ -59,11 +87,16 @@ CloudStream::CloudStream( QUrl& url, , m_num_requests_in_error( 0 ) , m_scriptResolver( scriptResolver ) , m_javascriptRefreshUrlFunction( javascriptRefreshUrlFunction ) + , m_javascriptCallbackFunction( javascriptCallbackFunction ) , m_refreshUrlEachTime( refreshUrlEachTime ) + , m_currentBlocklength( 0 ) + , m_cacheState( CloudStream::BeginningCache ) + , m_tags( QVariantMap() ) { m_network = TomahawkUtils::nam(); - tDebug( LOGINFO ) << "#### Cloudstream : CloudStream object created for " << m_filename << " : " - << m_url.toString(); + connect( this, SIGNAL( cacheReadFinished() ), this, SLOT( precache() ) ); + m_tags["fileId"] = fileId; + m_tags["mimetype"] = mimeType; } TagLib::FileName @@ -105,7 +138,7 @@ CloudStream::GetCached( int start, int end ) } void -CloudStream::Precache() +CloudStream::precache() { // For reading the tags of an MP3, TagLib tends to request: // 1. The first 1024 bytes @@ -120,23 +153,112 @@ CloudStream::Precache() // to support multipart byte ranges yet so we have to make do with two // requests. tDebug( LOGINFO ) << "#### CloudStream : Precaching from :" << m_filename; - seek( 0, TagLib::IOStream::Beginning ); - readBlock( kTaglibPrefixCacheBytes ); - seek( kTaglibSuffixCacheBytes, TagLib::IOStream::End ); - readBlock( kTaglibSuffixCacheBytes ); - clear(); - tDebug( LOGINFO ) << "#### CloudStream : Precaching end for :" << m_filename; + + switch( m_cacheState ) + { + case CloudStream::BeginningCache : + { + seek( 0, TagLib::IOStream::Beginning ); + readBlock( kTaglibPrefixCacheBytes ); + m_cacheState = CloudStream::EndCache; + break; + } + + case CloudStream::EndCache : + { + seek( kTaglibSuffixCacheBytes, TagLib::IOStream::End ); + readBlock( kTaglibSuffixCacheBytes ); + m_cacheState = CloudStream::EndCacheDone; + break; + } + + case CloudStream::EndCacheDone : + { + clear(); + // construct the tag map + QString mimeType = m_tags["mimetype"].toString(); + boost::scoped_ptr tag; + + if ( mimeType == "audio/mpeg" ) // && title.endsWith(".mp3")) + { + tag.reset(new TagLib::MPEG::File( + this, // Takes ownership. + TagLib::ID3v2::FrameFactory::instance(), + TagLib::AudioProperties::Accurate)); + } + else if ( mimeType == "audio/mp4" || ( mimeType == "audio/mpeg" ) ) // && title.endsWith(".m4a"))) + { + tag.reset( new TagLib::MP4::File( this, true, TagLib::AudioProperties::Accurate ) ); + } + else if ( mimeType == "application/ogg" || mimeType == "audio/ogg" ) + { + tag.reset( new TagLib::Ogg::Vorbis::File( this, true, TagLib::AudioProperties::Accurate ) ); + } + #ifdef TAGLIB_HAS_OPUS + else if ( mimeType == "application/opus" || mimeType == "audio/opus" ) + { + tag.reset( new TagLib::Ogg::Opus::File( this, true, TagLib::AudioProperties::Accurate ) ); + } + #endif + else if ( mimeType == "application/x-flac" || mimeType == "audio/flac" ) + { + tag.reset( new TagLib::FLAC::File( this, TagLib::ID3v2::FrameFactory::instance(), true, + TagLib::AudioProperties::Accurate ) ); + } + else if ( mimeType == "audio/x-ms-wma" ) + { + tag.reset( new TagLib::ASF::File( this, true, TagLib::AudioProperties::Accurate ) ); + } + else + { + tDebug( LOGINFO ) << "Unknown mime type for tagging:" << mimeType; + } + + if (this->num_requests() > 2) { + // Warn if pre-caching failed. + tDebug( LOGINFO ) << "Total requests for file:" << m_tags["fileId"] + << " : " << this->num_requests() << " with " + << this->cached_bytes() << " bytes cached"; + } + + //construction of the tag's map + if ( tag->tag() && !tag->tag()->isEmpty() ) + { + m_tags["track"] = tag->tag()->title().toCString( true ); + m_tags["artist"] = tag->tag()->artist().toCString( true ); + m_tags["album"] = tag->tag()->album().toCString( true ); + m_tags["size"] = QString::number( m_length ); + + if ( tag->tag()->track() != 0 ) + { + m_tags["albumpos"] = tag->tag()->track(); + } + if ( tag->tag()->year() != 0 ) + { + m_tags["year"] = tag->tag()->year(); + } + + if ( tag->audioProperties() ) + { + m_tags["duration"] = tag->audioProperties()->length(); + m_tags["bitrate"] = tag->audioProperties()->bitrate(); + } + } + emit tagsReady( m_tags, m_javascriptCallbackFunction ); + break; + } + } + } TagLib::ByteVector CloudStream::readBlock( ulong length ) { - const uint start = m_cursor; const uint end = qMin( m_cursor + length - 1, m_length - 1 ); - tDebug( LOGINFO ) << "#### CloudStream : parsing from " << m_url.toString(); - tDebug( LOGINFO ) << "#### CloudStream : parsing from (encoded) " << m_url.toEncoded().constData(); + //tDebug( LOGINFO ) << "#### CloudStream : parsing from " << m_url.toString(); + //tDebug( LOGINFO ) << "#### CloudStream : parsing from (encoded) " << m_url.toEncoded().constData(); if ( end < start ) { return TagLib::ByteVector(); @@ -151,6 +273,7 @@ CloudStream::readBlock( ulong length ) if ( m_num_requests_in_error > MAX_ALLOW_ERROR_QUERY ) { + //precache(); return TagLib::ByteVector(); } @@ -180,31 +303,34 @@ CloudStream::readBlock( ulong length ) request.setRawHeader( "Accept-Encoding", "identity" ); } - //tDebug() << request.rawHeader("Authorization"); tDebug() << "######## CloudStream : HTTP request : "; - foreach ( const QByteArray& header, request.rawHeaderList() ) - { - tDebug() << "#### CloudStream : header request : " << header << " = " << request.rawHeader(header); - } + tDebug() << "#### CloudStream : url : " << request.url(); + + m_currentBlocklength = length; + m_currentStart = start; + + m_reply = m_network->get( request ); + + connect( m_reply, SIGNAL( sslErrors( QList ) ), SLOT( SSLErrors( QList ) ) ); + connect( m_reply, SIGNAL( finished() ), this, SLOT( onRequestFinished() ) ); - QNetworkReply* reply = m_network->get( request ); - connect( reply, SIGNAL( sslErrors( QList ) ), SLOT( SSLErrors( QList ) ) ); ++m_num_requests; + return TagLib::ByteVector(); +} + + +void +CloudStream::onRequestFinished() +{ + m_reply->deleteLater(); - QEventLoop loop; - QObject::connect( reply, SIGNAL( finished() ), &loop, SLOT( quit() ) ); - loop.exec(); - reply->deleteLater(); + int code = m_reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt(); - int code = reply->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt(); tDebug() << "######### CloudStream : HTTP reply : #########"; tDebug( LOGINFO ) << "#### Cloudstream : HttpStatusCode : " << code; - foreach ( const QNetworkReply::RawHeaderPair& pair, reply->rawHeaderPairs() ) - { - tDebug( LOGINFO ) << "#### Cloudstream : header reply " << pair; - } + tDebug( LOGINFO ) << "#### Cloudstream : URL : " << m_reply->url(); - QByteArray data = reply->readAll(); + QByteArray data = m_reply->readAll(); if ( code != 206 ) { @@ -214,17 +340,14 @@ CloudStream::readBlock( ulong length ) if ( refreshStreamUrl() ) { - TagLib::ByteVector bytes = readBlock( length ); - //if we have datas, let another chance to parse ID3Tags (especially for Dropbox) - if( bytes.size() > 0 ){ - tDebug( LOGINFO ) << "#### Cloudstream : we have datas response with the refreshUrl !"; - m_num_requests_in_error--; - } - return bytes; + readBlock (m_currentBlocklength); + return; } else { - return TagLib::ByteVector(); + //return TagLib::ByteVector(); + precache(); + return ; } } @@ -232,10 +355,11 @@ CloudStream::readBlock( ulong length ) TagLib::ByteVector bytes( data.data(), data.size() ); m_cursor += data.size(); - FillCache( start, bytes ); - return bytes; + FillCache( m_currentStart, bytes ); + precache(); } + bool CloudStream::refreshStreamUrl() { @@ -246,7 +370,6 @@ CloudStream::refreshStreamUrl() tDebug( LOGINFO ) << "####### Cloudstream : refreshing streamUrl for " << m_filename; QString refreshUrl = QString( "resolver.%1( \"%2\" );" ).arg( m_javascriptRefreshUrlFunction ) .arg( m_fileId ); - tDebug( LOGINFO ) << "####### Cloudstream : refresh request : " << refreshUrl; QVariant response = m_scriptResolver->executeJavascript( refreshUrl ); if ( response.isNull() ) @@ -272,7 +395,6 @@ CloudStream::refreshStreamUrl() } m_url.setUrl( urlString ); - tDebug( LOGINFO ) << "####### Cloudstream : streamUrl refreshed for " << m_filename; return true; } diff --git a/src/libtomahawk/utils/CloudStream.h b/src/libtomahawk/utils/CloudStream.h index effcc73cdd..d05565ffa0 100644 --- a/src/libtomahawk/utils/CloudStream.h +++ b/src/libtomahawk/utils/CloudStream.h @@ -22,6 +22,7 @@ #include #include #include +#include ; #include @@ -29,6 +30,7 @@ class QNetworkAccessManager; class QtScriptResolver; +class QNetworkReply; class CloudStream : public QObject, public TagLib::IOStream { @@ -38,9 +40,11 @@ class CloudStream : public QObject, public TagLib::IOStream const QString& filename, const QString& fileId, const long length, + const QString& mimeType, QVariantMap& headers, QtScriptResolver *scriptResolver, const QString& javascriptRefreshUrlFunction, + const QString& javascriptCallbackFunction, const bool refreshUrlEachTime ); //Taglib::IOStream; @@ -72,19 +76,31 @@ class CloudStream : public QObject, public TagLib::IOStream return m_num_requests_in_error; } + bool refreshStreamUrl(); + +public slots: // Use educated guess to request the bytes that TagLib will probably want. - void Precache(); + void precache(); - bool refreshStreamUrl(); +signals: + void tagsReady( QVariantMap &, const QString & ); + void cacheReadFinished(); private: bool CheckCache( int start, int end ); void FillCache( int start, TagLib::ByteVector data ); TagLib::ByteVector GetCached( int start, int end ); + enum ReadingCacheState + { + BeginningCache, + EndCache, + EndCacheDone + }; private slots: void SSLErrors( const QList& errors ); + void onRequestFinished(); private: QUrl m_url; @@ -95,9 +111,15 @@ private slots: QVariantMap m_headers; const QString m_javascriptRefreshUrlFunction; const bool m_refreshUrlEachTime; + ulong m_currentBlocklength; + ReadingCacheState m_cacheState; + QVariantMap m_tags; + uint m_currentStart; + const QString m_javascriptCallbackFunction; int m_cursor; QNetworkAccessManager* m_network; + QNetworkReply* m_reply; QtScriptResolver* m_scriptResolver; google::sparsetable m_cache; From 60cfcf3ef514144ba6faba523f0860353d140da4 Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Tue, 9 Apr 2013 15:31:52 +0200 Subject: [PATCH 73/76] Remove addLocalJsFile. Now using resolver bundle. --- src/libtomahawk/resolvers/QtScriptResolver.cpp | 6 ------ src/libtomahawk/resolvers/QtScriptResolver.h | 2 -- 2 files changed, 8 deletions(-) diff --git a/src/libtomahawk/resolvers/QtScriptResolver.cpp b/src/libtomahawk/resolvers/QtScriptResolver.cpp index 37c0f3839e..e0c0cecf20 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.cpp +++ b/src/libtomahawk/resolvers/QtScriptResolver.cpp @@ -386,12 +386,6 @@ QtScriptResolverHelper::onTagReady( QVariantMap &tags, const QString& javascript m_resolver->m_engine->mainFrame()->evaluateJavaScript( getUrl ); } -void -QtScriptResolverHelper::addLocalJSFile( const QString &jsFilePath ) -{ - m_resolver->m_engine->mainFrame()->evaluateJavaScript( readRaw(jsFilePath) ); -} - void QtScriptResolverHelper::requestWebView(const QString &varName, const QString &url) diff --git a/src/libtomahawk/resolvers/QtScriptResolver.h b/src/libtomahawk/resolvers/QtScriptResolver.h index 6b991b9d70..86b2ea9ab0 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.h +++ b/src/libtomahawk/resolvers/QtScriptResolver.h @@ -70,8 +70,6 @@ Q_OBJECT const QString& mime_type, const QVariant& requestJS, const QString& javascriptCallbackFunction, const QString& javascriptRefreshUrlFunction = QString(), const bool refreshUrlEachTime = false ); - Q_INVOKABLE void addLocalJSFile(const QString& jsFilePath); - Q_INVOKABLE void requestWebView(const QString& varName, const QString& url); Q_INVOKABLE void showWebInspector(); From 4606a7598a48f38ffbd6be8228e48c01e4f89117 Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Wed, 10 Apr 2013 20:57:36 +0200 Subject: [PATCH 74/76] Remove syncPostRequest from tomahawk.js Fix style error. --- data/js/tomahawk.js | 36 ++++---------------- src/libtomahawk/CMakeLists.txt | 2 -- src/libtomahawk/resolvers/QtScriptResolver.h | 3 -- 3 files changed, 7 insertions(+), 34 deletions(-) diff --git a/data/js/tomahawk.js b/data/js/tomahawk.js index 64b10141ba..fae9bc965d 100644 --- a/data/js/tomahawk.js +++ b/data/js/tomahawk.js @@ -243,42 +243,17 @@ Tomahawk.syncRequest = function(url, extraHeaders) } }; -Tomahawk.syncPostRequest = function(url, params, extraHeaders) -{ - var xmlHttpRequest = new XMLHttpRequest(); - xmlHttpRequest.open('POST', url, false); - - xmlHttpRequest.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); - xmlHttpRequest.setRequestHeader("Content-length", params.length); - xmlHttpRequest.setRequestHeader("Connection", "close"); - - if (extraHeaders) { - for(var headerName in extraHeaders) { - xmlHttpRequest.setRequestHeader(headerName, extraHeaders[headerName]); - } - } - - xmlHttpRequest.send(params); - - if (xmlHttpRequest.readyState == 4 && xmlHttpRequest.status == 200) { - return xmlHttpRequest; - } else if (xmlHttpRequest.readyState === 4) { - Tomahawk.log("Failed to do POST request: to: " + url); - Tomahawk.log("Status Code was: " + xmlHttpRequest.status); - } - - -}; - Tomahawk.asyncRequest = function(url, callback, extraHeaders) { var xmlHttpRequest = new XMLHttpRequest(); xmlHttpRequest.open('GET', url, true); + if (extraHeaders) { for(var headerName in extraHeaders) { xmlHttpRequest.setRequestHeader(headerName, extraHeaders[headerName]); } } + xmlHttpRequest.onreadystatechange = function() { if (xmlHttpRequest.readyState == 4 && xmlHttpRequest.status == 200) { callback.call(window, xmlHttpRequest); @@ -287,6 +262,7 @@ Tomahawk.asyncRequest = function(url, callback, extraHeaders) Tomahawk.log("Status Code was: " + xmlHttpRequest.status); } } + xmlHttpRequest.send(null); }; @@ -296,14 +272,15 @@ Tomahawk.asyncPostRequest = function(url, params, callback, extraHeaders) xmlHttpRequest.open('POST', url, true); xmlHttpRequest.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); - xmlHttpRequest.setRequestHeader("Content-length", params.length); - xmlHttpRequest.setRequestHeader("Connection", "close"); + xmlHttpRequest.setRequestHeader('Content-length', params.length); + xmlHttpRequest.setRequestHeader('Connection', 'close'); if (extraHeaders) { for(var headerName in extraHeaders) { xmlHttpRequest.setRequestHeader(headerName, extraHeaders[headerName]); } } + xmlHttpRequest.onreadystatechange = function() { if (xmlHttpRequest.readyState == 4 && xmlHttpRequest.status == 200) { callback.call(window, xmlHttpRequest); @@ -312,6 +289,7 @@ Tomahawk.asyncPostRequest = function(url, params, callback, extraHeaders) Tomahawk.log("Status Code was: " + xmlHttpRequest.status); } } + xmlHttpRequest.send(params); }; diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 58c3f68424..6959e802b6 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -331,8 +331,6 @@ list(APPEND libSources thirdparty/kdsingleapplicationguard/kdsharedmemorylocker.cpp thirdparty/kdsingleapplicationguard/kdtoolsglobal.cpp thirdparty/kdsingleapplicationguard/kdlockedsharedmemorypointer.cpp - - ) IF(LIBLASTFM_FOUND) diff --git a/src/libtomahawk/resolvers/QtScriptResolver.h b/src/libtomahawk/resolvers/QtScriptResolver.h index 86b2ea9ab0..fd9e7f5474 100644 --- a/src/libtomahawk/resolvers/QtScriptResolver.h +++ b/src/libtomahawk/resolvers/QtScriptResolver.h @@ -36,9 +36,6 @@ #include #include -#include -#include - #ifdef QCA2_FOUND #include #endif From 8179ce2e24b2008ed393952e396d7f7d39f3fcc2 Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Thu, 11 Apr 2013 13:12:40 +0200 Subject: [PATCH 75/76] Change function name in tomahawk.js to asyncFormPostRequest. --- data/js/tomahawk.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/js/tomahawk.js b/data/js/tomahawk.js index fae9bc965d..8b6d1fdf36 100644 --- a/data/js/tomahawk.js +++ b/data/js/tomahawk.js @@ -266,7 +266,7 @@ Tomahawk.asyncRequest = function(url, callback, extraHeaders) xmlHttpRequest.send(null); }; -Tomahawk.asyncPostRequest = function(url, params, callback, extraHeaders) +Tomahawk.asyncFormPostRequest = function(url, params, callback, extraHeaders) { var xmlHttpRequest = new XMLHttpRequest(); xmlHttpRequest.open('POST', url, true); From efd39971fc886af460effbdb385849f5c65c0007 Mon Sep 17 00:00:00 2001 From: AltarBeastiful Date: Wed, 24 Apr 2013 17:30:22 +0200 Subject: [PATCH 76/76] Update with the duration with the new result and track interface. --- src/AudioControls.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AudioControls.cpp b/src/AudioControls.cpp index 923403e3c8..9ee18bd06a 100644 --- a/src/AudioControls.cpp +++ b/src/AudioControls.cpp @@ -234,9 +234,9 @@ AudioControls::onPlaybackStarted( const Tomahawk::result_ptr& result ) qint64 duration = AudioEngine::instance()->currentTrackTotalTime(); - //TODO : check if result.data()->duration() is always valid + //TODO : check if result->track()->duration() is always valid if ( duration <= 0 ) - duration = result.data()->duration() * 1000; + duration = result->track()->duration() * 1000; ui->seekSlider->setRange( 0, duration ); ui->seekSlider->setValue( 0 );