[weboob] [PATCH 2/2] Added ultimateguitar module

Rudy Weber webrudy at gmail.com
Sun Mar 2 23:26:53 CET 2014


Signed-off-by: Rudy Weber <webrudy at gmail.com>
---
 modules/ultimateguitar/__init__.py |   24 ++++++++++
 modules/ultimateguitar/backend.py  |   55 ++++++++++++++++++++++
 modules/ultimateguitar/browser.py  |   71 ++++++++++++++++++++++++++++
 modules/ultimateguitar/favicon.png |  Bin 0 -> 3339 bytes
 modules/ultimateguitar/pages.py    |   89 ++++++++++++++++++++++++++++++++++++
 modules/ultimateguitar/test.py     |   37 +++++++++++++++
 6 files changed, 276 insertions(+)
 create mode 100644 modules/ultimateguitar/__init__.py
 create mode 100644 modules/ultimateguitar/backend.py
 create mode 100644 modules/ultimateguitar/browser.py
 create mode 100644 modules/ultimateguitar/favicon.png
 create mode 100644 modules/ultimateguitar/pages.py
 create mode 100644 modules/ultimateguitar/test.py

diff --git a/modules/ultimateguitar/__init__.py b/modules/ultimateguitar/__init__.py
new file mode 100644
index 0000000..07a31d2
--- /dev/null
+++ b/modules/ultimateguitar/__init__.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2014      Rudy Weber
+#
+# This file is part of weboob.
+#
+# weboob is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# weboob 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with weboob. If not, see <http://www.gnu.org/licenses/>.
+
+
+from .backend import UltimateguitarBackend
+
+
+__all__ = ['UltimateguitarBackend']
diff --git a/modules/ultimateguitar/backend.py b/modules/ultimateguitar/backend.py
new file mode 100644
index 0000000..8663185
--- /dev/null
+++ b/modules/ultimateguitar/backend.py
@@ -0,0 +1,55 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2014      Rudy Weber
+#
+# This file is part of weboob.
+#
+# weboob is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# weboob 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with weboob. If not, see <http://www.gnu.org/licenses/>.
+
+
+from weboob.tools.backend import BaseBackend
+from weboob.capabilities.tab import ICapTab, SongTab
+
+from .browser import UltimateguitarBrowser
+
+from urllib import quote_plus
+
+__all__ = ['UltimateguitarBackend']
+
+
+class UltimateguitarBackend(BaseBackend, ICapTab):
+    NAME = 'ultimateguitar'
+    DESCRIPTION = u'ultimateguitar website'
+    MAINTAINER = u'Rudy Weber'
+    EMAIL = 'webrudy at gmail.com'
+    LICENSE = 'AGPLv3+'
+    VERSION = '0.i'
+
+    BROWSER = UltimateguitarBrowser
+
+    def get_tab(self, id):
+        return self.browser.get_tab(id)
+
+    def iter_tab(self, criteria, pattern):
+        return self.browser.iter_tab(criteria, quote_plus(pattern.encode('utf-8')))
+
+    def fill_tab(self, songtab, fields):
+        if 'content' in fields:
+            tmp = self.get_tab(songtab.id)
+            if tmp.url != None:
+                songtab.url = tmp.url
+            songtab.content = tmp.content
+        return songtab
+
+    OBJECTS = {SongTab: fill_tab}
diff --git a/modules/ultimateguitar/browser.py b/modules/ultimateguitar/browser.py
new file mode 100644
index 0000000..2512d1f
--- /dev/null
+++ b/modules/ultimateguitar/browser.py
@@ -0,0 +1,71 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2014      Rudy Weber
+#
+# This file is part of weboob.
+#
+# weboob is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# weboob 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with weboob. If not, see <http://www.gnu.org/licenses/>.
+
+
+from weboob.tools.browser import BaseBrowser, BrowserHTTPNotFound
+
+from .pages import SearchPage, TabPage
+
+
+__all__ = ['UltimateguitarBrowser']
+
+
+class UltimateguitarBrowser(BaseBrowser):
+    PROTOCOL = 'http'
+    DOMAIN = 'www.ultimate-guitar.com'
+    SUBDOMAIN = 'tabs.ultimate-guitar.com'
+    ENCODING = 'utf-8'
+    USER_AGENT = BaseBrowser.USER_AGENTS['wget']
+
+    PAGES = {
+        '%s://%s/search\.php\?title=.+' % (PROTOCOL, DOMAIN): SearchPage,
+        '%s://%s/./.+/.+\.htm' % (PROTOCOL, SUBDOMAIN): TabPage,
+    }
+
+    def get_type(self, _type):
+        return {
+            'all': '0',
+            'tab': '200',
+            'chords': '300',
+            'bass': '400',
+            'gp': '500',
+            'powertab': '600',
+            'drum': '700',
+            'ukulele': '800'}.get(_type, None)
+
+    def iter_tab(self, criteria, pattern):
+        addr = '%s://%s/search.php?title=%s' % (self.PROTOCOL, self.DOMAIN, pattern)
+        _type = self.get_type(criteria)
+        if _type is None:
+            print "Unknown criteria %s" % criteria
+            return {}
+        if _type is not '0':
+            addr += '&type=%s' % _type
+
+        self.location(addr)
+        assert self.is_on_page(SearchPage)
+        return self.page.iter_tab(criteria)
+
+    def get_tab(self, _id):
+        try:
+            self.location('%s://%s/%s' % (self.PROTOCOL, self.SUBDOMAIN, _id))
+        except BrowserHTTPNotFound:
+            return
+        assert self.is_on_page(TabPage)
+        return self.page.get_tab()
diff --git a/modules/ultimateguitar/favicon.png b/modules/ultimateguitar/favicon.png
new file mode 100644
index 0000000000000000000000000000000000000000..1fcbea0dc891112b6607ee41ceea76bbac691e3a
GIT binary patch
literal 3339
zcmZ`*WmJ^W+I<;n7*bjV1q1{JaE9(2T1py;p+V_x5Cj}RQo37*MjD0?rKKb#1tbOO
zj*H*->;AawtbO*{`>eg5^W!|vIw%b_1!Bkp2mk=YN{WaVcP#Y}V9?#pLb!&yBODuP
zRcQdIjwQS@!@bj3ZZ8yMfQliy%{#$hq4+`-0DM^iAowi+T-;f~8vx(|1Ar|g0Enal
z0F85Iv!>YH0iL;v0s^@Gw{kHhiFXcxlf1m!KfVJ1T(hj>{S(fL2LDXO|ATzrYl(lR
zr?a%p9smCg3wK`b0RUm45<*(rc45abz~0!#=T>~!PhvNsa_6kHI&0b`b4^q=xG?8+
zLH%nPj_~vZQhpYzhZZ5D;qUEA*(k0H<SZU+ at iB62#F25#hvQA0VN3VKMFx9J;5p!a
z0I{E|**~pwa%~?L{(JZ*)@^5cYU-rUVoGLZ0yEZhnt7PLe(HadecD=xK67}~ItRKU
z>2M|7yL}YQdmh2Ts=%j8r_puDMH8&=&N|49W=m!?W|x9}_9ghFOTiw`Md@(_L6L*e
zdvp$J6j+;<_F=!_Z#lF(c{`l7rQcQ$j4n#jv>t`)u_dy7TQUxH2O;!FnT^Xg9G|YF
zH*}KVuq{>9Hy}Oy+^1TW8Y|cuvq4HahhckpPmhx*OjIs7G(ZSO5D*_mrGHt!{RlZ$
z9?)q at 4{xyNW#XGBDMa6%VERoZSIX^6VCl;n+Seh;&=>*$Vui>PyTS6ajD^0~Rv`&q
zS%1GBS663-p7=WvYIWc4ar{8g<?wVh_grf|H8wW5>@#8+-WjLn?=9`q0TBx|4>R at u
z4#a(`5dnzg&_hR}X&<n#P->F6A%<D1k7U{OagyKV0@&PLWd6G4g6o{Jl;QBBWB{Rs
znZa@%2=CWx9}xM((UY<&1ED04?;odbl))(-UmZMCWVMuS{an}D_K6O1e{3Mnt!9IU
zGl%PbPCU$(E|kLvzcR->x1Li7a11I53aHGaGg}PfNF{@SI<vPAT0|>az2S$LsI*$G
zfJYRrj0=l`&0p%&Z;N^DwiJ4PlaZG72fiAxTaiPrD1YWmZuhCUPD{)xiQN5~>4puY
zlIhp;5C?OJ4c9ho?Gq|`Gvu1b!w$yl-Mq at 1af&eW7Wk%yK^3dMM7U-7eVzDt@;@;f
zrbG4XPdq<PO5`o0RB1>mABrTYiXU%D$?3mYK#Zh7E)tWjU(4_A&<C9LU`x`f3W`<{
zBi}(o^F;ba?u9WLPFVyU at mk9u<6Txay)x(8crKF!eGlT#H at e-pOx)2M7dUJn=^&Af
z{d|90I&^>#g)%h;wY1mKs~-L`1~VyXBtRldMZK9?^+)2z{yF{AM~ki}ODfv~%EfPp
zN~%rD(33S;uRLbG3RsO8<s`lYU<zja<lB#;7GiJRtvbnpq%Bp%19shuJQr)eKsKSD
zr_}mw&iRKjGwx?US8YF+LX8|wYX_!i!nI7VRHx9-KRq-4G#$=CL=gghc?s$=%m`b)
z6g<j^p*9-of^~yVzd8 at 3sC)2<?lq!=3AE%R+q7{xMYwR`d1Sxn%ZpA)Np6>}B2yOn
zYkk0${Z at GCo@60NMD6GSTjX1)!YPlGj at xrQhR9;douA0|bJMwm?uKx~Hu3R4Fe7<J
z^SF8+UCLnc+(_!4{Ooyx2M~G_e#o!kD|Csxjy6>oIo>l9djb<<x8{v=YsZ9vXnz7x
z{4TCgwJW#&85iOoH=@&3982WhVly$?Mu3t9i?sqnN_AZm4olT!V?hW}fuzoTXp^i}
z1FI%pNMr{{V#U7ix_`4?5mgC+L-Bea?`U;=owJW5G|OB+GL3jno|h$avAlv3`v{30
zO(X)MKg|2v4i-`}LvmcQXpGT~RCze+!V|w0+D4<ON-R+XN}*D@!60;9k#!C54I*&T
zmnDkX+-iqNQHp1|4;1f-N}i-^RcXB$Yy1E at D^t>~3cP(`&54L8868K$%97&BLOvSm
z9Ncqsga-Odxv&{?w8&ZwTkRWAk;!$(S7zG<tywB`Yo<}_A;7YKS~OAHly6EWwQ!}{
z8?wqK(#{}Qy78X&Ei_Dgi}ZF%w7o~ACFEW at XVHmrx7#J6fj+`I)C)hew^j5I50~Zg
z6 at 5=)b~=cnr_=s$2s$oP-G9%7UKAnY2&wy|%u01NtT<5ViejE(FA}MsrMIaeG2?^9
zViqVwC#IZyKhG1MwzqPVn}+~sTb|U4z^-0u=iw9QfZJ$dVs)?$ZUFRr#IY|0T_OL`
zfwT<iWkVw0=2>6Pj6|<Dyj3J)8$6p4g4Z^u^BL9%8N0tU%HY|8`^zW9XEOqKz1Q%#
zDF=%;5%mg8H{Yy7OjvwVYUnT`7WzJooJqp;#3&?$m3K82k;Ty>Seq=srz0=xYCyb+
z0O2md#A0IYK-uGogYe!p=Ua!)N$DQtfMazmve(y>4z(5z-bG+*GL2fI+==%%8Vq*s
zI!tWIm_wFlW>O;wxt5h%>Thh+-8-vq8&}4=i=7K)X5v87AHkG)Of>mSZf^KYA3#Qn
z6alM&q{wVxqhdrISZb(;)Gg8Ji3*8D;~yz+*<yqgn<ayB;E}R`M=MfhG><31{5nkC
zNkXq)hr)`k6*hLXs(y)=5w+O3^S*u7|CfeSz39EVruu=X1bNcqHBT>-K7#Ki?L-9{
zUm_L?cFMc^?cFUP1vcSePX~bp$LiaCibSPf&-*0PRN5LuFPj7_9}*8P+S7R^NO!C5
z?y_Mwi`*9z61w_wE}%*FiNioHBVv81!dpDW+tPV;siPN*I+BRl1kHHRWk2e-yk1I}
z>|fy&DdhPV1NUFdQk&}^v at T8m?E!_A<@g9(jWu8 at s4@D*q?JuaDT0|2`?{=;_v?qC
zHZ_~O?%(#AsF<Fdhun4yOy#io_9=Nxk-6Rj>!*+iSob&7t+TQ~eRu6=p)-gKz4rSb
zdCVpKZwR(tRaRUKVoS~O+ at 8KJA`P5WDT=<E?-BUij|>9XcY3|T4JD7G7P6p_?Xe_{
zKE?na&g<>goXkm+ZzeBmz*dkIJqD{dzT;U<(7X8WD?ftlN$0=o_72MN+FlTnXu|pm
z)FXy(dz}UtYS<9AuHzO)s9qLroHyDT(S>Q{!qG3+(<N=}-lf5le^^}po|e{X*cBiF
zoU#dG#iZW|g?El9Dp9IszJ7}0Up(<oHls};^j>Y-_=R13Z(a{RrISHLRN;AJX`1?s
zgSU(v+hv=Ug0_ at 0h+4(hdNs1qAu8Z3_#TU6m1Zicj|VGP)+>YG*o at _4LQ|2+Po at O?
zzYrju*LfX}j5jLT+G|*iU1y|Gf?6O|gVW+t%KKC`JD+hX2OH>4`?ioV?PghhWhu`{
z`y24utpcJ34;KtrajQJaXXb2FI>{fr0sjWJo4dN&|6(2P-3S9f6-Zz$5A*KJ{+bg(
zxY=r?P~&X9<r<Rs5RVLMG0aWmsqn1`h11oWRAn(D(b&T&b?pW)gn-2s at 7}W_bJR^Z
z3Y;hBHYRbbsmyAerhZ at t2F!g+roBp=uJJHNsiuLcmosneNqSCZ`Ni#bKwNXVh^uw{
zT7Ii1Ew<LkZd<ij45`A2FB8l<?~pJ5DRi0-NwV;0b$~EvZ1oqd<)QbH#u-h-cz?7L
z0}VdFO0`z_I&{NuF{KHQ=ChEq-%;MB5tNW%&IkJ)P0WSgTu%%lX(=6 at ZWc}De8_s)
zSMct~5I?#=a|PZBp>ONC{EDqv(b!=dqbIyrr*^Zc`Qt-&i-Ey&p!%R}WHexiel|bM
ziuoS1`1z`Ax*8ITf7=iXnaOay`PlYLmY}pNz2)KAQVaAY-g8SDt|!Az53Kb&E4~kn
z`Y~rj{BV|cC32N3+ev=nM>m-0#LWss+Z0N+rs#PIe61yLrZ?iw6}FQ+h1Uu^t6JuM
z5S(i2UVC6c`id5d?_s$2rkgjBXl3lpv5Wm5n|Qf3?b<5iD3_k=qr*{~_U<&kr(*hP
z&2h at kwC50>z at zHxUpJxwiz{i=wkcRZH_fxavsXu}pNIAdGnG5smIEI{v}Gs<Htb_=
zehvTmE_fD?dzi2{6NXLO6D*_DcJ}u~@>Xvsrde81w~u#hmU_1Z71Nd>qTA>)WRQQ&
zJ%s}VgWpLN{&w|V1`)q^Z8LAq7<h@#9)F~*R9(w;Tn7SjBb%YA`{`#docIiJ016nZ
zfOz-A!i8+{7g2b~rf#R}?x{sA{oVbbFpP~}k|xjm-RGUfT~6QK(#+jT#KP6;jsPAQ
zoR15}!^Oj=4HpvO;T7SBL1Aza7;N&Ddhve+9GooetbP7>phWQW!Cip$Uj;2EYj-a*
xS1Ul<!<#|F%+ArB0md!N%>!p(yDJFef(dcKc-i~oQ2KWXKuJywQ6Ym2`47Ca5MclS

literal 0
HcmV?d00001

diff --git a/modules/ultimateguitar/pages.py b/modules/ultimateguitar/pages.py
new file mode 100644
index 0000000..343ded3
--- /dev/null
+++ b/modules/ultimateguitar/pages.py
@@ -0,0 +1,89 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2014      Rudy Weber
+#
+# This file is part of weboob.
+#
+# weboob is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# weboob 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with weboob. If not, see <http://www.gnu.org/licenses/>.
+
+
+from weboob.tools.browser import BasePage
+from weboob.capabilities.base import NotLoaded, NotAvailable
+from weboob.capabilities.tab import SongTab
+
+from hashlib import sha1
+import re
+
+__all__ = ['SearchPage', 'TabPage']
+
+
+class SearchPage(BasePage):
+    def iter_tab(self, criteria):
+        regex_artist = re.compile(r'/.*')
+
+        for result in self.document.getroot().cssselect('table.tresults tr td a.song:not(.search_art)'):
+            url = result.attrib.get('href', '')
+
+            if url.startswith('http://plus.'):
+                continue
+
+            _id = url.replace('http://tabs.ultimate-guitar.com/', '')
+            songtab = SongTab(_id, unicode(result.text_content()))
+            artist = unicode(regex_artist.sub('', _id[2:]).replace('_', ' ').replace('.htm', '').title())
+            songtab.artist = unicode(artist)
+            songtab.url = unicode(url)
+            songtab.type = _id[len(_id)-13:len(_id)-4]
+            if songtab.type.endswith('power_tab') and not songtab.title.lower().endswith('power'):
+                songtab.type = 'Power Tab'
+            elif songtab.type.endswith('ulele_crd'):
+                songtab.type = 'Ukulele Chords'
+            elif songtab.type.endswith('drum_tab'):
+                songtab.type = 'Drum'
+            elif songtab.type.endswith('_tab'):
+                songtab.type = 'ASCII Tab'
+            elif songtab.type.endswith('_crd'):
+                songtab.type = 'Chords'
+            elif songtab.type.endswith('_btab'):
+                songtab.type = 'Bass Tab'
+            elif songtab.type.endswith('uitar_pro'):
+                songtab.type = 'Guitar Pro'
+            songtab.content = NotLoaded
+
+            yield songtab
+
+
+class TabPage(BasePage):
+    def get_tab(self):
+        try:
+            self.browser.select_form(name="tab_download")
+            type = 'dl'
+        except:
+            type = None
+
+        songtab = SongTab(NotAvailable, NotAvailable)
+
+        if type is 'dl':
+            tab_id = self.browser['tab_id']
+            sess_id = self.browser['session_id']
+            token = sha1('onlyUG_'+tab_id).hexdigest()
+            songtab.url = u'http://www.ultimate-guitar.com/tab_download.php?tab_id=%s&session_id=%s&token=%s' % (tab_id, sess_id, token)
+            songtab.content = None
+            return songtab
+
+        for content in self.document.getroot().cssselect('div#cont pre:not(.print-visible)'):
+            songtab.content = unicode(content.text_content())
+
+        songtab.url = None
+
+        return songtab
diff --git a/modules/ultimateguitar/test.py b/modules/ultimateguitar/test.py
new file mode 100644
index 0000000..4ed668b
--- /dev/null
+++ b/modules/ultimateguitar/test.py
@@ -0,0 +1,37 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2014      Rudy Weber
+#
+# This file is part of weboob.
+#
+# weboob is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# weboob 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with weboob. If not, see <http://www.gnu.org/licenses/>.
+
+
+from weboob.tools.test import BackendTest
+from weboob.capabilities.base import NotLoaded
+
+class UltimateguitarTest(BackendTest):
+    BACKEND = 'ultimateguitar'
+
+    def test_ultimateguitar(self):
+        l_tab = list(self.backend.iter_tab('tab', 'metallica'))
+        for songtab in l_tab:
+            assert songtab.id
+            assert songtab.title
+            assert songtab.artist
+            assert songtab.type
+            assert songtab.url
+            assert songtab.content == NotLoaded
+            tab_content = self.backend.get_tab(songtab.id)
+            assert tab_content
-- 
1.7.9.5



More information about the weboob mailing list