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

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

Implemented cache

File size: 22.4 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        #def register
61
62        def enable(self,state=False):
63                self.disable=state
64        #def enable
65
66        def execute_action(self,action,applist=None,store=None):
67                if store:
68                        self.store=store
69                else:
70                        self.store=appstream.Store()
71                self.appimage_store=appstream.Store()
72                self.progress=0
73                self.result['status']={'status':-1,'msg':''}
74                self.result['data']=[]
75                self.threads=[]
76                dataList=[]
77                if self.disabled:
78                        self._set_status(9)
79                        self.result['data']=self.store
80                else:
81                        self._chk_installDir()
82                        if action=='load':
83                                self._load_appimage_store(self.store)
84                                #self._debug("Ending threads...")
85                                while not self.apps_for_store.empty():
86                                        app=self.apps_for_store.get()
87                                        self.store.add_app(app)
88                                self.result['data']=self.store
89                        else:
90                                for app_info in applist:
91                                        self.partial_progress=0
92                                        if action=='install':
93                                                dataList.append(self._install_appimage(app_info))
94                                        if action=='remove':
95                                                dataList.append(self._remove_appimage(app_info))
96                                        if action=='pkginfo':
97                                                dataList.append(self._get_info(app_info))
98                                        self.progress+=int(self.partial_progress/len(applist))-1
99                                self.result['data']=list(dataList)
100                self.progress=100
101                return(self.result)
102        #def execute_action
103
104        def _set_status(self,status,msg=''):
105                self.result['status']={'status':status,'msg':msg}
106        #def _set_status
107
108        def _callback(self,partial_size=0,total_size=0):
109                limit=99
110                if partial_size!=0 and total_size!=0:
111                        inc=round(partial_size/total_size,2)*100
112                        self.progress=inc
113                else:
114                        inc=1
115                        margin=limit-self.progress
116                        inc=round(margin/limit,3)
117                        self.progress=(self.progress+inc)
118                if (self.progress>limit):
119                        self.progress=limit
120        #def _callback
121
122        def _chk_installDir(self):
123                msg_status=True
124                if not os.path.isdir(self.appimage_dir):
125                        try:
126                                os.makedirs(self.appimage_dir)
127                        except:
128                                msg_status=False
129                return msg_status                               
130        #def _chk_installDir
131
132        def _install_appimage(self,app_info):
133                app_info=self._get_info(app_info,force=True)
134                #self._debug("Installing %s"%app_info)
135                if app_info['state']=='installed':
136                        self._set_status(4)
137                else:
138                        if 'appimage' in app_info['channel_releases'].keys():
139                                appimage_url=app_info['channel_releases']['appimage'][0]
140                        else:
141                                #self._debug("No url in: %s"%app_info['channel_releases'])
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                                        pass
222                return(store)
223        #def _generic_file_load
224
225        def _get_bundles_catalogue(self):
226                applist=[]
227                appdict={}
228                all_apps=[]
229                outdir=self.cache_xmls
230                #Load repos
231                for repo_name,repo_info in self.repos.items():
232                        if not os.path.isdir(self.cache_xmls):
233                                try:
234                                        os.makedirs(self.cache_xmls)
235                                except:
236                                        #self._debug("appImage catalogue could not be fetched: Permission denied")
237                                        pass
238                        #self._debug("Fetching repo %s"%repo_info['url'])
239                        if repo_info['type']=='json':
240                                applist=self._process_appimage_json(self._fetch_repo(repo_info['url']),repo_name)
241
242                        #self._debug("Fetched repo "+repo_info['url'])
243                        self._th_generate_xml_catalog(applist,outdir,repo_info['url_info'],repo_info['url'],repo_name)
244                        all_apps.extend(applist)
245                return True
246
247        def _get_external_catalogue(self):
248                applist=[]
249                all_apps=[]
250                outdir=self.cache_xmls
251                #Load external apps
252                for app_name,app_info in self._get_external_appimages().items():
253                        if os.path.isdir(self.cache_xmls):
254                                appinfo=self._init_appinfo()
255                                if 'name' in app_info.keys():
256                                        appinfo['name']=app_info['name']
257                                else:
258                                        appinfo['name']=app_info['url'].split('/')[-1]
259                                appinfo['package']=app_info['url'].split('/')[-1]
260                                if 'homepage' in app_info.keys():
261                                        appinfo['homepage']=app_info['homepage']
262                                else:
263                                        appinfo['homepage']='/'.join(app_info['url'].split('/')[0:-1])
264                                appinfo['installerUrl']=app_info['url']
265                                if 'description' in app_info.keys():
266                                        if type(app_info['description'])==type({}):
267                                                for lang in app_info['description']:
268                                                        appinfo['description'].update({lang:app_info['description'][lang]})
269                                        else:
270                                                appinfo['description'].update({"C":appimage['description']})
271                                if 'categories' in app_info.keys():
272                                        appinfo['categories']=app_info['categories']
273                                if 'keywords' in app_info.keys():
274                                        appinfo['keywords']=app_info['keywords']
275                                if 'version' in app_info.keys():
276                                        appinfo['reywords']=app_info['keywords']
277                                #self._debug("Fetching external appimage %s"%app_info['url'])
278                                appinfo['bundle']='appimage'
279                                #self._debug("External:\n%s\n-------"%appinfo)
280                                applist.append(appinfo)
281                        else:
282                                #self._debug("External appImage could not be fetched: Permission denied")
283                                pass
284                self._th_generate_xml_catalog(applist,outdir,app_info['url_info'],app_info['url'],app_name)
285                #self._debug("Fetched appimage "+app_info['url'])
286                all_apps.extend(applist)
287                #self._debug("Removing old entries...")
288#               self._clean_bundle_catalogue(all_apps,outdir)
289                return(True)
290        #def _get_bundles_catalogue
291       
292        def _fetch_repo(self,repo):
293                req=Request(repo, headers={'User-Agent':'Mozilla/5.0'})
294                with urllib.request.urlopen(req) as f:
295                        content=(f.read().decode('utf-8'))
296               
297                return(content)
298        #def _fetch_repo
299       
300        def _get_external_appimages(self):
301                external_appimages={}
302                if os.path.isfile(self.external_appimages):
303                        try:
304                                with open(self.external_appimages) as appimages:
305                                        external_appimages=json.load(appimages)
306                        except:
307                                #self._debug("Can't load %s"%self.external_appimages)
308                                pass
309                return external_appimages
310        #def _get_external_appimages
311       
312        def _process_appimage_json(self,data,repo_name):
313                applist=[]
314                json_data=json.loads(data)
315                if 'items' in json_data.keys():
316                        for appimage in json_data['items']:
317                                appinfo=self._th_process_appimage(appimage)
318                                if appinfo:
319                                        applist.append(appinfo)
320                return (applist)
321        #_process_appimage_json
322
323        def _th_process_appimage(self,appimage):
324                appinfo=None
325                releases=[]
326                if 'links' in appimage.keys():
327                        if appimage['links']:
328                                appinfo=self.load_json_appinfo(appimage)
329                return(appinfo)
330        #def _th_process_appimage
331
332        def load_json_appinfo(self,appimage):
333                #self._debug(appimage)
334                appinfo=self._init_appinfo()
335                appinfo['name']=appimage['name']
336                appinfo['package']=appimage['name']
337                if 'license' in appimage.keys():
338                        appinfo['license']=appimage['license']
339                appinfo['summary']=''
340                if 'description' in appimage.keys():
341                        if type(appimage['description'])==type({}):
342                                for lang in appinfo['description'].keys():
343                                        appinfo['description'].update({lang:appimage['description'][lang]})
344                        else:
345                                appinfo['description']={"C":appimage['description']}
346                if 'categories' in appimage.keys():
347                        appinfo['categories']=appimage['categories']
348                if 'icon' in appimage.keys():
349                        appinfo['icon']=appimage['icon']
350                if 'icons' in appimage.keys():
351                        #self._debug("Loading icon %s"%appimage['icons'])
352                        if appimage['icons']:
353                                #self._debug("Loading icon %s"%appimage['icons'][0])
354                                appinfo['icon']=appimage['icons'][0]
355                if 'screenshots' in appimage.keys():
356                        appinfo['thumbnails']=appimage['screenshots']
357                if 'links' in appimage.keys():
358                        if appimage['links']:
359                                for link in appimage['links']:
360                                        if 'url' in link.keys() and link['type']=='Download':
361                                                appinfo['installerUrl']=link['url']
362                if 'authors' in appimage.keys():
363                        if appimage['authors']:
364                                for author in appimage['authors']:
365                                        if 'url' in author.keys():
366                                                #self._debug("Author: %s"%author['url'])
367                                                appinfo['homepage']=author['url']
368                else:
369                        appinfo['homepage']='/'.join(appinfo['installerUrl'].split('/')[0:-1])
370                appinfo['bundle']=['appimage']
371                return appinfo
372        #def load_json_appinfo
373
374        def _th_generate_xml_catalog(self,applist,outdir,info_url,repo,repo_name):
375                maxconnections = 2
376                threads=[]
377                semaphore = threading.BoundedSemaphore(value=maxconnections)
378                random_applist = list(applist)
379                random.shuffle(random_applist)
380                for app in applist:
381                        th=threading.Thread(target=self._th_write_xml, args = (app,outdir,info_url,repo,repo_name,semaphore))
382                        threads.append(th)
383                        th.start()
384                for thread in threads:
385                        thread.join()
386        #def _th_generate_xml_catalog
387
388        def     _th_write_xml(self,appinfo,outdir,info_url,repo,repo_name,semaphore):
389                semaphore.acquire()
390                self._add_appimage(appinfo)
391                semaphore.release()
392        #def _th_write_xml
393
394        def _add_appimage(self,appinfo):
395                #Search in local store for the app
396                sw_new=True
397                app=appstream.App()
398                app_orig=self.store.get_app_by_pkgname(appinfo['name'].lower())
399                if not app_orig:
400                        app_orig=self.store.get_app_by_id(appinfo['name'].lower()+".desktop")
401                if app_orig:
402                        #self._debug("Extending app %s"%appinfo['package'])
403                        if appinfo['icon']:
404                                #self._debug("Icon: %s"%appinfo['icon'])
405                                app=self._copy_app_from_appstream(app_orig,app,copy_icon=False)
406                        else:
407                                app=self._copy_app_from_appstream(app_orig,app,copy_icon=True)
408                        sw_new=False
409                else:
410                        #self._debug("Generating new %s"%appinfo['package'])
411                        pass
412                if appinfo['name'].endswith('.appimage'):
413                        app.set_id("appimagehub.%s"%appinfo['name'].lower())
414                        app.set_name("C",appinfo['name'])
415                else:
416                        app.set_id("appimagehub.%s"%appinfo['name'].lower()+'.appimage')
417                        app.set_name("C",appinfo['name']+".appimage")
418                if appinfo['package'].endswith('.appimage'):
419                        app.add_pkgname(appinfo['package'].lower())
420                else:
421                        app.add_pkgname(appinfo['package'].lower()+".appimage")
422                app.set_id_kind=appstream.IdKind.DESKTOP
423
424                if appinfo['license']:
425                        app.set_project_license(appinfo['license'])
426                bundle=appstream.Bundle()
427                bundle.set_kind(bundle.kind_from_string('APPIMAGE'))
428                if appinfo['package'].endswith('.appimage'):
429                        bundle.set_id(appinfo['package'])
430                else:
431                        bundle.set_id(appinfo['package']+'.appimage')
432                app.add_bundle(bundle)
433                if 'keywords' in appinfo.keys():
434                        for keyword in appinfo['keywords']:
435                                app.add_keyword("C",keyword)
436                        if 'appimage' not in appinfo['keywords']:
437                                app.add_keyword("C","appimage")
438                else:
439                        app.add_keyword("C","appimage")
440                app.add_url(appstream.UrlKind.UNKNOWN,appinfo['installerUrl'])
441                app.add_url(appstream.UrlKind.HOMEPAGE,appinfo['homepage'])
442                if sw_new:
443                        app.add_keyword("C",appinfo['package'])
444                        if not appinfo['name'].endswith('.appimage'):
445                                app.set_name("C",appinfo['name']+".appimage")
446                        desc_header="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']
447                        if appinfo['description']:
448                                for lang,desc in appinfo['description'].items():
449                                        desc=desc.replace('&','&amp;')
450                                        description="<p>%s</p><p>%s</p>"%(desc_header,desc)
451                                        summary=' '.join(list(desc.split(' ')[:10]))
452                                        app.set_description(lang,description)
453                                        app.set_comment(lang,summary)
454                        else:
455                                description="<p>%s</p>"%(desc_header)
456                                summary=' '.join(list(desc_header.split(' ')[:8]))
457                                app.set_description("C",description)
458                                app.set_comment("C",summary)
459
460                        if 'categories' in appinfo.keys():
461                                for category in appinfo['categories']:
462                                        app.add_category(category)
463                                if 'appimage' not in appinfo['categories']:
464                                        app.add_category("appimage")
465                        else:
466                                app.add_category("appimage")
467                if appinfo['icon']:
468                        icon=appstream.Icon()
469                        if self.icon_cache_enabled:
470                                icon.set_kind(appstream.IconKind.LOCAL)
471                                icon_fn=self._download_file(appinfo['icon'],appinfo['name'],self.icons_dir)
472                                icon.set_filename(icon_fn)
473                        else:
474                                icon.set_kind(appstream.IconKind.REMOTE)
475                                icon.set_name(pkg.get_icon())
476                                icon.set_url(pkg.get_icon())
477                        app.add_icon(icon)
478                if appinfo['thumbnails']:
479                        screenshot=appstream.Screenshot()
480                        img=appstream.Image()
481                        if not appinfo['thumbnails'][0].startswith('http'):
482                                        appinfo['screenshot']=appinfo['thumbnails'][0]
483                                        appinfo['screenshot']="https://appimage.github.io/database/%s"%appinfo['screenshot']
484                        img.set_kind(appstream.ImageKind.SOURCE)
485                        img.set_url(appinfo['screenshot'])
486                        screenshot.add_image(img)
487                        app.add_screenshot(screenshot)
488                #Adds the app to the store
489                self.apps_for_store.put(app)
490                if not os.path.isfile(self.cache_xmls+'/'+app.get_id_filename()):
491                        xml_path='%s/%s.xml'%(self.cache_xmls,app.get_id_filename())
492                        gioFile=Gio.File.new_for_path(xml_path)
493                        app.to_file(gioFile)
494                        #Fix some things in app_file...
495                        xml_file=open(xml_path,'r',encoding='utf-8')
496                        xml_data=xml_file.readlines()
497                        xml_file.close()
498                        #self._debug("fixing %s"%xml_path)
499                        try:
500                                xml_data[0]=xml_data[0]+"<components origin=\"%s\">\n"%app.get_origin()
501                                xml_data[-1]=xml_data[-1]+"\n"+"</components>"
502                        except:
503                                pass
504                        xml_file=open(xml_path,'w')
505                        xml_file.writelines(xml_data)
506                        xml_file.close()
507        #def _add_appimage
508
509        def _copy_app_from_appstream(self,app_orig,app,copy_icon=True):
510                desc_header="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."%app_orig.get_pkgnames()[0]
511                app.set_id("appimage."+app_orig.get_id())
512                for category in app_orig.get_categories():
513                        app.add_category(category)
514                app.add_category("appimage")
515                for screenshot in app_orig.get_screenshots():
516                        app.add_screenshot(screenshot)
517                if copy_icon:
518                        for icon in app_orig.get_icons():
519                                app.add_icon(icon)
520                for localeItem in self.locale:
521                        if app_orig.get_name(localeItem):
522                                app.set_name(localeItem,app_orig.get_name(localeItem)+".appimage")
523                        if app_orig.get_description(localeItem):
524                                app.set_description(localeItem,"<p>%s</p><p>%s</p>"%(desc_header,app_orig.get_description(localeItem)))
525                        if app_orig.get_comment(localeItem):
526                                app.set_comment(localeItem,app_orig.get_comment(localeItem))
527                app.set_origin(app_orig.get_origin())
528                return app
529        #def _copy_app_from_appstream
530
531        def _clean_bundle_catalogue(self,applist,outdir):
532                xml_files_list=[]
533                applist=[item.lower() for item in applist]
534                for xml_file in os.listdir(outdir):
535                        if xml_file.endswith('.xml'):
536                                xml_files_list.append(xml_file.lower().replace('.xml','appimage'))
537       
538                if xml_files_list:
539                        xml_discard_list=list(set(xml_files_list).difference(applist))
540                        for discarded_file in xml_discard_list:
541                                os.remove(outdir+'/'+discarded_file.replace('appimage','.xml'))
542        #def _clean_bunlde_catalogue
543
544        def _download_file(self,url,app_name,dest_dir):
545                target_file=dest_dir+'/'+app_name+".png"
546                if not url.startswith('http'):
547                        url="https://appimage.github.io/database/%s"%url
548                if not os.path.isfile(target_file):
549                        if not os.path.isfile(target_file):
550                                #self._debug("Downloading %s to %s"%(url,target_file))
551                                try:
552                                        with urllib.request.urlopen(url) as response, open(target_file, 'wb') as out_file:
553                                                bf=16*1024
554                                                acumbf=0
555                                                file_size=int(response.info()['Content-Length'])
556                                                while True:
557                                                        if acumbf>=file_size:
558                                                            break
559                                                        shutil.copyfileobj(response, out_file,bf)
560                                                        acumbf=acumbf+bf
561                                        st = os.stat(target_file)
562                                except Exception as e:
563                                        #self._debug("Unable to download %s"%url)
564                                        #self._debug("Reason: %s"%e)
565                                        target_file=''
566                return(target_file)
567        #def _download_file
568       
569        def _chk_bundle_dir(self,outdir):
570                msg_status=True
571                if not os.path.isdir(outdir):
572                        try:
573                                os.makedirs(outdir)
574                        except Exception as e:
575                                msg_status=False
576                                print(e)
577                return(os.access(outdir,os.W_OK|os.R_OK|os.X_OK|os.F_OK))
578        #def _chk_bundle_dir
579       
580        def _init_appinfo(self):
581                appInfo={'appstream_id':'',\
582                'id':'',\
583                'name':'',\
584                'version':'',\
585                'channel_releases':{},\
586                'component':'',\
587                'package':'',\
588                'license':'',\
589                'summary':'',\
590                'description':{},\
591                'categories':[],\
592                'icon':'',\
593                'screenshot':'',\
594                'thumbnails':[],\
595                'video':'',\
596                'homepage':'',\
597                'installerUrl':'',\
598                'state':'',\
599                'depends':'',\
600                'kudos':'',\
601                'suggests':'',\
602                'extraInfo':'',\
603                'size':'',\
604                'bundle':'',\
605                'updatable':'',\
606                }
607                return(appInfo)
608        #def _init_appinfo
609       
610        def _get_info(self,app_info,force=False):
611                #self._debug("Searching for %s in %s"%(app_info['package'],self.appimage_dir))
612                app_info['state']='available'
613                if os.path.isfile(self.appimage_dir+'/'+app_info['package']):
614                        app_info['state']='installed'
615                if not app_info['size'] or force:
616                        if app_info['installerUrl']:
617                                #self._debug("installer: %s"%app_info['installerUrl'])
618                                app_info['channel_releases']={'appimage':[]}
619                                app_info['channel_releases']['appimage']=self._get_releases(app_info)
620                        #Get size
621                        app_info['size']=0
622                        app_info['version']='unknown'
623                        if 'appimage' in app_info['channel_releases'].keys():
624                                if len(app_info['channel_releases']['appimage'])>0:
625                                        if app_info['channel_releases']['appimage'][0]:
626                                                appimage_url=app_info['channel_releases']['appimage'][0]
627                                                dest_path=self.appimage_dir+'/'+app_info['package']
628                                                if appimage_url:
629                                                        try:
630                                                                with urllib.request.urlopen(appimage_url) as response:
631                                                                        app_info['size']=(response.info()['Content-Length'])
632                                                        except:
633                                                                app_info['size']=0
634                                        #Version (unaccurate aprox)
635                                        app_info['version']=app_info['channel_releases']['appimage'][0].split('/')[-2]
636
637                self._set_status(0)
638                self.partial_progress=100
639                return(app_info)
640        #def _get_info
641
642        def _get_releases(self,app_info):
643                releases=[]
644                releases_page=''
645                #self._debug("Info url: %s"%app_info['installerUrl'])
646                url_source=""
647                try:
648                        if 'github' in app_info['installerUrl']:
649                                releases_page="https://github.com"
650                        if 'gitlab' in app_info['installerUrl']:
651                                releases_page="https://gitlab.com"
652                        if 'opensuse' in app_info['installerUrl'].lower():
653                                releases_page=""
654                                url_source="opensuse"
655#                               app_info['installerUrl']=app_info['installerUrl']+"/download"
656
657                        if url_source or releases_page:
658                                with urllib.request.urlopen(app_info['installerUrl']) as f:
659                                        content=(f.read().decode('utf-8'))
660                                        soup=BeautifulSoup(content,"html.parser")
661                                        package_a=soup.findAll('a', attrs={ "href" : re.compile(r'.*\.[aA]pp[iI]mage$')})
662
663                                        for package_data in package_a:
664                                                if url_source=="opensuse":
665                                                        package_name=package_data.findAll('a', attrs={"class" : "mirrorbrain-btn"})
666                                                else:
667                                                        package_name=package_data.findAll('strong', attrs={ "class" : "pl-1"})
668                                                package_link=package_data['href']
669                                                if releases_page or url_source:
670                                                        package_link=releases_page+package_link
671                                                        releases.append(package_link)
672                                                        #self._debug("Link: %s"%package_link)
673                        else:
674                                releases=[app_info['installerUrl']]
675                except Exception as e:
676                        print(e)
677                #self._debug(releases)
678                return releases
679        #def _get_releases
680       
Note: See TracBrowser for help on using the repository browser.