source: lliurex-store/trunk/fuentes/python3-lliurex-store.install/usr/share/lliurexstore/plugins/appImageManager.py @ 8185

Last change on this file since 8185 was 8185, checked in by Juanma, 13 months ago

improved cache icons

File size: 21.6 KB
Line 
1#The name of the main class must match the file name in lowercase
2import re
3import urllib
4from urllib.request import Request
5from urllib.request import urlretrieve
6import shutil
7import json
8import os
9import sys
10import threading
11import queue
12import time
13import random
14import gi
15from gi.repository import Gio
16gi.require_version('AppStreamGlib', '1.0')
17from gi.repository import AppStreamGlib as appstream
18from bs4 import BeautifulSoup
19#from subprocess import call
20
21class appimagemanager:
22        def __init__(self):
23                self.dbg=False
24                self.progress=0
25                self.partial_progress=0
26                self.plugin_actions={'install':'appimage','remove':'appimage','pkginfo':'appimage','load':'appimage'}
27                self.result={}
28                self.result['data']={}
29                self.result['status']={}
30                self.cache_dir=os.getenv("HOME")+"/.cache/lliurex-store"
31                self.icons_dir=self.cache_dir+"/icons"
32                self.cache_xmls=self.cache_dir+"/xmls/appimage"
33                self.appimage_dir=os.getenv("HOME")+"/.local/bin"
34                #To get the description of an app we must go to a specific url defined in url_info.
35                #$(appname) we'll be replaced with the appname so the url matches the right one.
36                #If other site has other url naming convention it'll be mandatory to define it with the appropiate replacements
37                self.repos={'appimagehub':{'type':'json','url':'https://appimage.github.io/feed.json','url_info':''}}
38                #Appimges not stored in a repo must be listed in this file, providing the download url and the info url (if there's any)
39                self.external_appimages="/usr/share/lliurex-store/files/external_appimages.json"
40                self.locale=['ca_ES@valencia','ca@valencia','qcv','ca','ca_ES','es_ES','es','en_US','en_GB','en','C']
41                self.disabled=False
42                self.icon_cache_enabled=True
43                self.image_cache_enabled=True
44                self.cache_last_update=self.cache_xmls+'/.appimage.lu'
45                self.apps_for_store=queue.Queue()
46        #def __init__
47
48        def set_debug(self,dbg=True):
49                self.dbg=dbg
50                self._debug ("Debug enabled")
51        #def set_debug
52
53        def _debug(self,msg=''):
54                if self.dbg:
55                        print ('DEBUG appimage: %s'%msg)
56        #def debug
57
58        def register(self):
59                return(self.plugin_actions)
60
61        def enable(self,state=False):
62                self.disable=state
63
64        def execute_action(self,action,applist=None,store=None):
65                if store:
66                        self.store=store
67                else:
68                        self.store=appstream.Store()
69                self.appimage_store=appstream.Store()
70                self.progress=0
71                self.result['status']={'status':-1,'msg':''}
72                self.result['data']=[]
73                self.threads=[]
74                dataList=[]
75                if self.disabled:
76                        self._set_status(9)
77                        self.result['data']=self.store
78                else:
79                        self._chk_installDir()
80                        if action=='load':
81                                self._load_appimage_store(self.store)
82                                #wait till threads end (if any)
83                                self._debug("Ending threads...")
84                                for th in threading.enumerate():
85                                        if th.is_alive():
86                                                try:
87                                                        th.join(5)
88                                                except:
89                                                        pass
90                                while not self.apps_for_store.empty():
91                                        app=self.apps_for_store.get()
92                                        self.store.add_app(app)
93                                self.result['data']=self.store
94                        else:
95                                for app_info in applist:
96                                        self.partial_progress=0
97                                        if action=='install':
98                                                dataList.append(self._install_appimage(app_info))
99                                        if action=='remove':
100                                                dataList.append(self._remove_appimage(app_info))
101                                        if action=='pkginfo':
102                                                dataList.append(self._get_info(app_info))
103                                        self.progress+=int(self.partial_progress/len(applist))-1
104                                self.result['data']=list(dataList)
105                self.progress=100
106                return(self.result)
107
108        def _set_status(self,status,msg=''):
109                self.result['status']={'status':status,'msg':msg}
110        #def _set_status
111
112        def _callback(self,partial_size=0,total_size=0):
113                limit=99
114                if partial_size!=0 and total_size!=0:
115                        inc=round(partial_size/total_size,2)*100
116                        self.progress=inc
117                else:
118                        inc=1
119                        margin=limit-self.progress
120                        inc=round(margin/limit,3)
121                        self.progress=(self.progress+inc)
122                if (self.progress>limit):
123                        self.progress=limit
124
125        def _chk_installDir(self):
126                msg_status=True
127                if not os.path.isdir(self.appimage_dir):
128                        try:
129                                os.makedirs(self.appimage_dir)
130                        except:
131                                msg_status=False
132                return msg_status                               
133
134        def _install_appimage(self,app_info):
135                app_info=self._get_info(app_info)
136                self._debug("Installing %s"%app_info)
137                if app_info['state']=='installed':
138                        self._set_status(4)
139                else:
140                        if 'appimage' in app_info['channel_releases'].keys():
141                                appimage_url=app_info['channel_releases']['appimage'][0]
142                        self._debug("Downloading "+appimage_url)
143                        dest_path=self.appimage_dir+'/'+app_info['package']
144                        if appimage_url:
145                                try:
146                                        req=Request(appimage_url, headers={'User-Agent':'Mozilla/5.0'})
147                                        with urllib.request.urlopen(req) as response, open(dest_path, 'wb') as out_file:
148                                                bf=16*1024
149                                                acumbf=0
150                                                app_size=int(response.info()['Content-Length'])
151                                                while True:
152                                                        if acumbf>=app_size:
153                                                            break
154                                                        shutil.copyfileobj(response, out_file,bf)
155                                                        acumbf=acumbf+bf
156                                                        self._callback(acumbf,app_size)
157                                        st = os.stat(dest_path)
158                                        os.chmod(dest_path, st.st_mode | 0o111)
159                                        self._set_status(0)
160                                except Exception as e:
161                                        print(e)
162                                        self._set_status(5)
163                        else:
164                                self._set_status(12)
165                return app_info
166        #def _install_appimage
167
168        def _remove_appimage(self,app_info):
169                self._debug("Removing "+app_info['package'])
170                if os.path.isfile(self.appimage_dir+'/'+app_info['package']):
171                        try:
172                                call([self.appimage_dir+"/"+app_info['package'], "--remove-appimage-desktop-integration"])
173                        except:
174                                pass
175                        try:
176                                os.remove(self.appimage_dir+"/"+app_info['package'])
177                                self._set_status(0)
178                        except:
179                                self._set_status(6)
180                return(app_info)
181        #def _remove_appimage
182
183        def _load_appimage_store(self,store):
184                #Look if cache is up-to-date
185                sw_update_cache=True
186                if os.path.isfile(self.cache_last_update):
187                        epoch_time=time.time()
188                        fcache=open(self.cache_last_update,'r')
189                        fcache_update=fcache.read()
190                        if not fcache_update:
191                                fcache_update=0
192                        if int(epoch_time)-int(fcache_update)<86400:
193                                if os.listdir(os.path.dirname(self.cache_xmls)):
194                                        self._debug("Loading appimage from cache")
195                                        sw_update_cache=False
196                if sw_update_cache:
197                        self._get_bundles_catalogue()
198                        self._get_external_catalogue()
199                        fcache=open(self.cache_last_update,'w')
200                        fcache.write(str(int(time.time())))
201                if os.path.exists(self.cache_xmls):
202                        self._debug("Loading appimage catalog")
203                        store=self._generic_file_load(self.cache_xmls,store)
204                return(store)
205        #def load_bundles_catalog(self)
206       
207        def _generic_file_load(self,target_path,store):
208                icon_path='/usr/share/icons/hicolor/128x128'
209                if not os.path.isdir(target_path):
210                        os.makedirs(target_path)
211                files=os.listdir(target_path)
212                for target_file in os.listdir(target_path):
213                        if target_file.endswith('.xml'):
214                                store_path=Gio.File.new_for_path(target_path+'/'+target_file)
215                                self._debug("Adding file "+target_path+'/'+target_file)
216                                try:
217                                        store.from_file(store_path,icon_path,None)
218                                except Exception as e:
219                                        self._debug("Couldn't add file "+target_file+" to store")
220                                        self._debug("Reason: "+str(e))
221                return(store)
222        #def _generic_file_load
223
224        def _get_bundles_catalogue(self):
225                applist=[]
226                appdict={}
227                all_apps=[]
228                outdir=self.cache_xmls
229                #Load repos
230                for repo_name,repo_info in self.repos.items():
231                        if not os.path.isdir(self.cache_xmls):
232                                try:
233                                        os.makedirs(self.cache_xmls)
234                                except:
235                                        self._debug("appImage catalogue could not be fetched: Permission denied")
236                        self._debug("Fetching repo %s"%repo_info['url'])
237                        if repo_info['type']=='json':
238                                applist=self._process_appimage_json(self._fetch_repo(repo_info['url']),repo_name)
239
240                        self._debug("Fetched repo "+repo_info['url'])
241                        self._th_generate_xml_catalog(applist,outdir,repo_info['url_info'],repo_info['url'],repo_name)
242                        all_apps.extend(applist)
243                return True
244
245        def _get_external_catalogue(self):
246                applist=[]
247                all_apps=[]
248                outdir=self.cache_xmls
249                #Load external apps
250                for app_name,app_info in self._get_external_appimages().items():
251                        if os.path.isdir(self.cache_xmls):
252                                appinfo=self._init_appinfo()
253                                if 'name' in app_info.keys():
254                                        appinfo['name']=app_info['name']
255                                else:
256                                        appinfo['name']=app_info['url'].split('/')[-1]
257                                appinfo['package']=app_info['url'].split('/')[-1]
258                                if 'homepage' in app_info.keys():
259                                        appinfo['homepage']=app_info['homepage']
260                                else:
261                                        appinfo['homepage']='/'.join(app_info['url'].split('/')[0:-1])
262                                appinfo['installerUrl']=app_info['url']
263                                if 'description' in app_info.keys():
264                                        if type(app_info['description'])==type({}):
265                                                for lang in app_info['description']:
266                                                        appinfo['description'].update({lang:app_info['description'][lang]})
267                                        else:
268                                                appinfo['description'].update({"C":appimage['description']})
269                                if 'categories' in app_info.keys():
270                                        appinfo['categories']=app_info['categories']
271                                if 'keywords' in app_info.keys():
272                                        appinfo['keywords']=app_info['keywords']
273                                if 'version' in app_info.keys():
274                                        appinfo['reywords']=app_info['keywords']
275                                self._debug("Fetching external appimage %s"%app_info['url'])
276                                appinfo['bundle']='appimage'
277                                self._debug("External:\n%s\n-------"%appinfo)
278                                applist.append(appinfo)
279                        else:
280                                self._debug("External appImage could not be fetched: Permission denied")
281                self._th_generate_xml_catalog(applist,outdir,app_info['url_info'],app_info['url'],app_name)
282                self._debug("Fetched appimage "+app_info['url'])
283                all_apps.extend(applist)
284                self._debug("Removing old entries...")
285#               self._clean_bundle_catalogue(all_apps,outdir)
286                return(True)
287        #def _get_bundles_catalogue
288       
289        def _fetch_repo(self,repo):
290                req=Request(repo, headers={'User-Agent':'Mozilla/5.0'})
291                with urllib.request.urlopen(req) as f:
292                        content=(f.read().decode('utf-8'))
293               
294                return(content)
295        #def _fetch_repo
296       
297        def _get_external_appimages(self):
298                external_appimages={}
299                if os.path.isfile(self.external_appimages):
300                        try:
301                                with open(self.external_appimages) as appimages:
302                                        external_appimages=json.load(appimages)
303                        except:
304                                self._debug("Can't load %s"%self.external_appimages)
305                return external_appimages
306        #def _get_external_appimages
307       
308        def _process_appimage_json(self,data,repo_name):
309                applist=[]
310                json_data=json.loads(data)
311                if 'items' in json_data.keys():
312                        for appimage in json_data['items']:
313                                appinfo=self._th_process_appimage(appimage)
314                                if appinfo:
315                                        applist.append(appinfo)
316                return (applist)
317        #_process_appimage_json
318
319        def _th_process_appimage(self,appimage):
320                appinfo=None
321                releases=[]
322                if 'links' in appimage.keys():
323                        if appimage['links']:
324                                appinfo=self.load_json_appinfo(appimage)
325                return(appinfo)
326        #def _th_process_appimage
327
328        def load_json_appinfo(self,appimage):
329                self._debug(appimage)
330                appinfo=self._init_appinfo()
331                appinfo['name']=appimage['name']
332                appinfo['package']=appimage['name']
333                if 'license' in appimage.keys():
334                        appinfo['license']=appimage['license']
335                appinfo['summary']=''
336                if 'description' in appimage.keys():
337                        if type(appimage['description'])==type({}):
338                                for lang in appinfo['description'].keys():
339                                        appinfo['description'].update({lang:appimage['description'][lang]})
340                        else:
341                                appinfo['description']={"C":appimage['description']}
342                if 'categories' in appimage.keys():
343                        appinfo['categories']=appimage['categories']
344                if 'icon' in appimage.keys():
345                        appinfo['icon']=appimage['icon']
346                if 'icons' in appimage.keys():
347                        self._debug("Loading icon %s"%appimage['icons'])
348                        if appimage['icons']:
349                                self._debug("Loading icon %s"%appimage['icons'][0])
350                                appinfo['icon']=appimage['icons'][0]
351                if 'screenshots' in appimage.keys():
352                        appinfo['thumbnails']=appimage['screenshots']
353                if 'links' in appimage.keys():
354                        if appimage['links']:
355                                for link in appimage['links']:
356                                        if 'url' in link.keys() and link['type']=='Download':
357                                                appinfo['installerUrl']=link['url']
358                if 'authors' in appimage.keys():
359                        if appimage['authors']:
360                                for author in appimage['authors']:
361                                        if 'url' in author.keys():
362                                                self._debug("Author: %s"%author['url'])
363                                                appinfo['homepage']=author['url']
364                else:
365                        appinfo['homepage']='/'.join(appinfo['installerUrl'].split('/')[0:-1])
366                appinfo['bundle']=['appimage']
367                return appinfo
368        #def load_json_appinfo
369
370        def _th_generate_xml_catalog(self,applist,outdir,info_url,repo,repo_name):
371                maxconnections = 2
372                threads=[]
373                semaphore = threading.BoundedSemaphore(value=maxconnections)
374                random_applist = list(applist)
375                random.shuffle(random_applist)
376                for app in applist:
377                        th=threading.Thread(target=self._th_write_xml, args = (app,outdir,info_url,repo,repo_name,semaphore))
378                        threads.append(th)
379                        th.start()
380        #def _th_generate_xml_catalog
381
382        def     _th_write_xml(self,appinfo,outdir,info_url,repo,repo_name,semaphore):
383                semaphore.acquire()
384                self._add_appimage(appinfo)
385                semaphore.release()
386        #def _th_write_xml
387
388        def _add_appimage(self,appinfo):
389                #Search in local store for the app
390                sw_new=False
391                app=appstream.App()
392                app_orig=self.store.get_app_by_pkgname(appinfo['name'].lower())
393                if not app_orig:
394                        app_orig=self.store.get_app_by_id(appinfo['name'].lower()+".desktop")
395                if app_orig:
396                        self._debug("Extending app %s"%appinfo['package'])
397                        app=self._copy_app_from_appstream(app_orig,app)
398                else:
399                        self._debug("Generating new %s"%appinfo['package'])
400                if appinfo['name'].endswith('.appimage'):
401                        app.set_id("appimagehub.%s"%appinfo['name'].lower())
402                        app.set_name("C",appinfo['name'])
403                else:
404                        app.set_id("appimagehub.%s"%appinfo['name'].lower()+'.appimage')
405                        app.set_name("C",appinfo['name']+".appimage")
406                if appinfo['package'].endswith('.appimage'):
407                        app.add_pkgname(appinfo['package'].lower())
408                else:
409                        app.add_pkgname(appinfo['package'].lower()+".appimage")
410                app.set_id_kind=appstream.IdKind.DESKTOP
411                sw_new=True
412
413                if appinfo['license']:
414                        app.set_project_license(appinfo['license'])
415                bundle=appstream.Bundle()
416                bundle.set_kind(bundle.kind_from_string('APPIMAGE'))
417                if appinfo['package'].endswith('.appimage'):
418                        bundle.set_id(appinfo['package'])
419                else:
420                        bundle.set_id(appinfo['package']+'.appimage')
421                app.add_bundle(bundle)
422                if 'keywords' in appinfo.keys():
423                        for keyword in appinfo['keywords']:
424                                app.add_keyword("C",keyword)
425                        if 'appimage' not in appinfo['keywords']:
426                                app.add_keyword("C","appimage")
427                else:
428                        app.add_keyword("C","appimage")
429                app.add_url(appstream.UrlKind.UNKNOWN,appinfo['installerUrl'])
430                app.add_url(appstream.UrlKind.HOMEPAGE,appinfo['homepage'])
431                if sw_new:
432                        app.add_keyword("C",appinfo['package'])
433                        if not appinfo['name'].endswith('.appimage'):
434                                app.set_name("C",appinfo['name']+".appimage")
435                        if appinfo['description']:
436                                for lang,desc in appinfo['description'].items():
437                                        description="This is an AppImage bundle of app %s. It hasn't been tested by our developers and comes from a 3rd party dev team. Please use it carefully.\n%s"%(appinfo['name'],desc)
438                                        summary=' '.join(list(description.split(' ')[:8]))
439                                        app.set_description(lang,description)
440                                        app.set_comment(lang,summary)
441                        else:
442                                description="This is an AppImage bundle of app %s. It hasn't been tested by our developers and comes from a 3rd party dev team. Please use it carefully"%(appinfo['name'])
443                                summary=' '.join(list(description.split(' ')[:8]))
444                                app.set_description("C",description)
445                                app.set_comment("C",summary)
446
447                        if 'categories' in appinfo.keys():
448                                for category in appinfo['categories']:
449                                        app.add_category(category)
450                                if 'appimage' not in appinfo['categories']:
451                                        app.add_category("appimage")
452                        else:
453                                app.add_category("appimage")
454                if appinfo['icon']:
455                        icon=appstream.Icon()
456                        if self.icon_cache_enabled:
457                                icon.set_kind(appstream.IconKind.LOCAL)
458                                icon_fn=self._download_file(appinfo['icon'],appinfo['name'],self.icons_dir)
459                                icon.set_filename(icon_fn)
460                        else:
461                                icon.set_kind(appstream.IconKind.REMOTE)
462                                icon.set_name(pkg.get_icon())
463                                icon.set_url(pkg.get_icon())
464                        app.add_icon(icon)
465                if appinfo['thumbnails']:
466                        screenshot=appstream.Screenshot()
467                        img=appstream.Image()
468                        if not appinfo['thumbnails'][0].startswith('http'):
469                                        appinfo['screenshot']=appinfo['thumbnails'][0]
470                                        appinfo['screenshot']="https://appimage.github.io/database/%s"%appinfo['screenshot']
471                        img.set_kind(appstream.ImageKind.SOURCE)
472                        img.set_url(appinfo['screenshot'])
473                        screenshot.add_image(img)
474                        app.add_screenshot(screenshot)
475                #Adds the app to the store
476                self.apps_for_store.put(app)
477                if not os.path.isfile(self.cache_xmls+'/'+app.get_id_filename()):
478                        xml_path='%s/%s.xml'%(self.cache_xmls,app.get_id_filename())
479                        gioFile=Gio.File.new_for_path(xml_path)
480                        app.to_file(gioFile)
481                        #Fix some things in app_file...
482                        xml_file=open(xml_path,'r',encoding='utf-8')
483                        xml_data=xml_file.readlines()
484                        xml_file.close()
485                        self._debug("fixing %s"%xml_path)
486                        try:
487                                xml_data[0]=xml_data[0]+"<components>\n"
488                                xml_data[-1]=xml_data[-1]+"\n"+"</components>"
489                        except:
490                                pass
491                        xml_file=open(xml_path,'w')
492                        xml_file.writelines(xml_data)
493                        xml_file.close()
494
495        #def _add_appimage
496
497        def _copy_app_from_appstream(self,app_orig,app):
498                app.set_id("appimage."+app_orig.get_id())
499                for category in app_orig.get_categories():
500                        app.add_category(category)
501                for screenshot in app_orig.get_screenshots():
502                        app.add_screenshot(screenshot)
503                for icon in app_orig.get_icons():
504                        app.add_icon(icon)
505                for localeItem in self.locale:
506                        if app_orig.get_name(localeItem):
507                                app.set_name(localeItem,app_orig.get_name(localeItem)+".appimage")
508                        if app_orig.get_description(localeItem):
509                                app.set_description(localeItem,app_orig.get_description(localeItem))
510                        if app_orig.get_comment(localeItem):
511                                app.set_comment(localeItem,app_orig.get_comment(localeItem))
512                app.set_origin(app_orig.get_origin())
513                return app
514
515        def _clean_bundle_catalogue(self,applist,outdir):
516                xml_files_list=[]
517                applist=[item.lower() for item in applist]
518                for xml_file in os.listdir(outdir):
519                        if xml_file.endswith('.xml'):
520                                xml_files_list.append(xml_file.lower().replace('.xml','appimage'))
521       
522                if xml_files_list:
523                        xml_discard_list=list(set(xml_files_list).difference(applist))
524                        for discarded_file in xml_discard_list:
525                                os.remove(outdir+'/'+discarded_file.replace('appimage','.xml'))
526        #def _clean_bunlde_catalogue
527
528        def _download_file(self,url,app_name,dest_dir):
529                target_file=dest_dir+'/'+app_name+".png"
530                if not url.startswith('http'):
531                        url="https://appimage.github.io/database/%s"%url
532                if not os.path.isfile(target_file):
533                        if not os.path.isfile(target_file):
534                                self._debug("Downloading %s to %s"%(url,target_file))
535                                try:
536                                        with urllib.request.urlopen(url) as response, open(target_file, 'wb') as out_file:
537                                                bf=16*1024
538                                                acumbf=0
539                                                file_size=int(response.info()['Content-Length'])
540                                                while True:
541                                                        if acumbf>=file_size:
542                                                            break
543                                                        shutil.copyfileobj(response, out_file,bf)
544                                                        acumbf=acumbf+bf
545                                        st = os.stat(target_file)
546                                except Exception as e:
547                                        self._debug("Unable to download %s"%url)
548                                        self._debug("Reason: %s"%e)
549                                        target_file=''
550                return(target_file)
551        #def _download_file
552       
553        def _chk_bundle_dir(self,outdir):
554                msg_status=True
555                if not os.path.isdir(outdir):
556                        try:
557                                os.makedirs(outdir)
558                        except Exception as e:
559                                msg_status=False
560                                print(e)
561                return(os.access(outdir,os.W_OK|os.R_OK|os.X_OK|os.F_OK))
562        #def _chk_bundle_dir
563       
564        def _init_appinfo(self):
565                appInfo={'appstream_id':'',\
566                'id':'',\
567                'name':'',\
568                'version':'',\
569                'channel_releases':{},\
570                'component':'',\
571                'package':'',\
572                'license':'',\
573                'summary':'',\
574                'description':{},\
575                'categories':[],\
576                'icon':'',\
577                'screenshot':'',\
578                'thumbnails':[],\
579                'video':'',\
580                'homepage':'',\
581                'installerUrl':'',\
582                'state':'',\
583                'depends':'',\
584                'kudos':'',\
585                'suggests':'',\
586                'extraInfo':'',\
587                'size':'',\
588                'bundle':'',\
589                'updatable':'',\
590                }
591                return(appInfo)
592        #def _init_appinfo
593       
594        def _get_info(self,app_info):
595                if app_info['installerUrl']:
596                        self._debug("installer: %s"%app_info['installerUrl'])
597                        app_info['channel_releases']={'appimage':[]}
598                        app_info['channel_releases']['appimage']=self._get_releases(app_info)
599                app_info['state']='available'
600                if os.path.isfile(self.appimage_dir+'/'+app_info['package']):
601                        app_info['state']='installed'
602                #Get size
603                if 'appimage' in app_info['channel_releases'].keys():
604                        if app_info['channel_releases']['appimage'][0]:
605                                appimage_url=app_info['channel_releases']['appimage'][0]
606                                dest_path=self.appimage_dir+'/'+app_info['package']
607                                if appimage_url:
608                                        try:
609                                                with urllib.request.urlopen(appimage_url) as response:
610                                                        app_info['size']=(response.info()['Content-Length'])
611                                        except:
612                                                app_info['size']=0
613                        else:
614                                app_info['size']=0
615                        #Version (unaccurate aprox)
616                        app_info['version']=app_info['channel_releases']['appimage'][0].split('/')[-2]
617
618                self._set_status(0)
619                self.partial_progress=100
620                return(app_info)
621        #def _get_info
622
623        def _get_releases(self,app_info):
624                releases=[]
625                releases_page=''
626                self._debug("Info url: %s"%app_info['installerUrl'])
627                url_source=""
628                try:
629                        if 'github' in app_info['installerUrl']:
630                                releases_page="https://github.com"
631                        if 'gitlab' in app_info['installerUrl']:
632                                releases_page="https://gitlab.com"
633                        if 'opensuse' in app_info['installerUrl'].lower():
634                                releases_page=""
635                                url_source="opensuse"
636#                               app_info['installerUrl']=app_info['installerUrl']+"/download"
637
638                        if url_source or releases_page:
639                                with urllib.request.urlopen(app_info['installerUrl']) as f:
640                                        content=(f.read().decode('utf-8'))
641                                        soup=BeautifulSoup(content,"html.parser")
642                                        package_a=soup.findAll('a', attrs={ "href" : re.compile(r'.*\.[aA]pp[iI]mage$')})
643
644                                        for package_data in package_a:
645                                                if url_source=="opensuse":
646                                                        package_name=package_data.findAll('a', attrs={"class" : "mirrorbrain-btn"})
647                                                else:
648                                                        package_name=package_data.findAll('strong', attrs={ "class" : "pl-1"})
649                                                package_link=package_data['href']
650                                                if releases_page or url_source:
651                                                        package_link=releases_page+package_link
652                                                        releases.append(package_link)
653                                                        self._debug("Link: %s"%package_link)
654                        else:
655                                releases=[app_info['installerUrl']]
656                except Exception as e:
657                        print(e)
658                self._debug(releases)
659                return releases
660        #def _get_releases
661       
Note: See TracBrowser for help on using the repository browser.