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

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

Fix indent

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                                pass
143                        #self._debug("Downloading "+appimage_url)
144                        dest_path=self.appimage_dir+'/'+app_info['package']
145                        if appimage_url:
146                                try:
147                                        req=Request(appimage_url, headers={'User-Agent':'Mozilla/5.0'})
148                                        with urllib.request.urlopen(req) as response, open(dest_path, 'wb') as out_file:
149                                                bf=16*1024
150                                                acumbf=0
151                                                app_size=int(response.info()['Content-Length'])
152                                                while True:
153                                                        if acumbf>=app_size:
154                                                            break
155                                                        shutil.copyfileobj(response, out_file,bf)
156                                                        acumbf=acumbf+bf
157                                                        self._callback(acumbf,app_size)
158                                        st = os.stat(dest_path)
159                                        os.chmod(dest_path, st.st_mode | 0o111)
160                                        self._set_status(0)
161                                except Exception as e:
162                                        print(e)
163                                        self._set_status(5)
164                        else:
165                                self._set_status(12)
166                return app_info
167        #def _install_appimage
168
169        def _remove_appimage(self,app_info):
170                #self._debug("Removing "+app_info['package'])
171                if os.path.isfile(self.appimage_dir+'/'+app_info['package']):
172                        try:
173                                call([self.appimage_dir+"/"+app_info['package'], "--remove-appimage-desktop-integration"])
174                        except:
175                                pass
176                        try:
177                                os.remove(self.appimage_dir+"/"+app_info['package'])
178                                self._set_status(0)
179                        except:
180                                self._set_status(6)
181                return(app_info)
182        #def _remove_appimage
183
184        def _load_appimage_store(self,store):
185                #Look if cache is up-to-date
186                sw_update_cache=True
187                if os.path.isfile(self.cache_last_update):
188                        epoch_time=time.time()
189                        fcache=open(self.cache_last_update,'r')
190                        fcache_update=fcache.read()
191                        if not fcache_update:
192                                fcache_update=0
193                        if int(epoch_time)-int(fcache_update)<86400:
194                                if os.listdir(os.path.dirname(self.cache_xmls)):
195                                        #self._debug("Loading appimage from cache")
196                                        sw_update_cache=False
197                if sw_update_cache:
198                        self._get_bundles_catalogue()
199                        self._get_external_catalogue()
200                        fcache=open(self.cache_last_update,'w')
201                        fcache.write(str(int(time.time())))
202                if os.path.exists(self.cache_xmls):
203                        #self._debug("Loading appimage catalog")
204                        store=self._generic_file_load(self.cache_xmls,store)
205                return(store)
206        #def load_bundles_catalog(self)
207       
208        def _generic_file_load(self,target_path,store):
209                icon_path='/usr/share/icons/hicolor/128x128'
210                if not os.path.isdir(target_path):
211                        os.makedirs(target_path)
212                files=os.listdir(target_path)
213                for target_file in os.listdir(target_path):
214                        if target_file.endswith('.xml'):
215                                store_path=Gio.File.new_for_path(target_path+'/'+target_file)
216                                #self._debug("Adding file "+target_path+'/'+target_file)
217                                try:
218                                        store.from_file(store_path,icon_path,None)
219                                except Exception as e:
220                                        #self._debug("Couldn't add file "+target_file+" to store")
221                                        #self._debug("Reason: "+str(e))
222                                        pass
223                return(store)
224        #def _generic_file_load
225
226        def _get_bundles_catalogue(self):
227                applist=[]
228                appdict={}
229                all_apps=[]
230                outdir=self.cache_xmls
231                #Load repos
232                for repo_name,repo_info in self.repos.items():
233                        if not os.path.isdir(self.cache_xmls):
234                                try:
235                                        os.makedirs(self.cache_xmls)
236                                except:
237                                        #self._debug("appImage catalogue could not be fetched: Permission denied")
238                                        pass
239                        #self._debug("Fetching repo %s"%repo_info['url'])
240                        if repo_info['type']=='json':
241                                applist=self._process_appimage_json(self._fetch_repo(repo_info['url']),repo_name)
242
243                        #self._debug("Fetched repo "+repo_info['url'])
244                        self._th_generate_xml_catalog(applist,outdir,repo_info['url_info'],repo_info['url'],repo_name)
245                        all_apps.extend(applist)
246                return True
247
248        def _get_external_catalogue(self):
249                applist=[]
250                all_apps=[]
251                outdir=self.cache_xmls
252                #Load external apps
253                for app_name,app_info in self._get_external_appimages().items():
254                        if os.path.isdir(self.cache_xmls):
255                                appinfo=self._init_appinfo()
256                                if 'name' in app_info.keys():
257                                        appinfo['name']=app_info['name']
258                                else:
259                                        appinfo['name']=app_info['url'].split('/')[-1]
260                                appinfo['package']=app_info['url'].split('/')[-1]
261                                if 'homepage' in app_info.keys():
262                                        appinfo['homepage']=app_info['homepage']
263                                else:
264                                        appinfo['homepage']='/'.join(app_info['url'].split('/')[0:-1])
265                                appinfo['installerUrl']=app_info['url']
266                                if 'description' in app_info.keys():
267                                        if type(app_info['description'])==type({}):
268                                                for lang in app_info['description']:
269                                                        appinfo['description'].update({lang:app_info['description'][lang]})
270                                        else:
271                                                appinfo['description'].update({"C":appimage['description']})
272                                if 'categories' in app_info.keys():
273                                        appinfo['categories']=app_info['categories']
274                                if 'keywords' in app_info.keys():
275                                        appinfo['keywords']=app_info['keywords']
276                                if 'version' in app_info.keys():
277                                        appinfo['reywords']=app_info['keywords']
278                                #self._debug("Fetching external appimage %s"%app_info['url'])
279                                appinfo['bundle']='appimage'
280                                #self._debug("External:\n%s\n-------"%appinfo)
281                                applist.append(appinfo)
282                        else:
283                                #self._debug("External appImage could not be fetched: Permission denied")
284                                pass
285                self._th_generate_xml_catalog(applist,outdir,app_info['url_info'],app_info['url'],app_name)
286                #self._debug("Fetched appimage "+app_info['url'])
287                all_apps.extend(applist)
288                #self._debug("Removing old entries...")
289#               self._clean_bundle_catalogue(all_apps,outdir)
290                return(True)
291        #def _get_bundles_catalogue
292       
293        def _fetch_repo(self,repo):
294                req=Request(repo, headers={'User-Agent':'Mozilla/5.0'})
295                with urllib.request.urlopen(req) as f:
296                        content=(f.read().decode('utf-8'))
297               
298                return(content)
299        #def _fetch_repo
300       
301        def _get_external_appimages(self):
302                external_appimages={}
303                if os.path.isfile(self.external_appimages):
304                        try:
305                                with open(self.external_appimages) as appimages:
306                                        external_appimages=json.load(appimages)
307                        except:
308                                #self._debug("Can't load %s"%self.external_appimages)
309                                pass
310                return external_appimages
311        #def _get_external_appimages
312       
313        def _process_appimage_json(self,data,repo_name):
314                applist=[]
315                json_data=json.loads(data)
316                if 'items' in json_data.keys():
317                        for appimage in json_data['items']:
318                                appinfo=self._th_process_appimage(appimage)
319                                if appinfo:
320                                        applist.append(appinfo)
321                return (applist)
322        #_process_appimage_json
323
324        def _th_process_appimage(self,appimage):
325                appinfo=None
326                releases=[]
327                if 'links' in appimage.keys():
328                        if appimage['links']:
329                                appinfo=self.load_json_appinfo(appimage)
330                return(appinfo)
331        #def _th_process_appimage
332
333        def load_json_appinfo(self,appimage):
334                #self._debug(appimage)
335                appinfo=self._init_appinfo()
336                appinfo['name']=appimage['name']
337                appinfo['package']=appimage['name']
338                if 'license' in appimage.keys():
339                        appinfo['license']=appimage['license']
340                appinfo['summary']=''
341                if 'description' in appimage.keys():
342                        if type(appimage['description'])==type({}):
343                                for lang in appinfo['description'].keys():
344                                        appinfo['description'].update({lang:appimage['description'][lang]})
345                        else:
346                                appinfo['description']={"C":appimage['description']}
347                if 'categories' in appimage.keys():
348                        appinfo['categories']=appimage['categories']
349                if 'icon' in appimage.keys():
350                        appinfo['icon']=appimage['icon']
351                if 'icons' in appimage.keys():
352                        #self._debug("Loading icon %s"%appimage['icons'])
353                        if appimage['icons']:
354                                #self._debug("Loading icon %s"%appimage['icons'][0])
355                                appinfo['icon']=appimage['icons'][0]
356                if 'screenshots' in appimage.keys():
357                        appinfo['thumbnails']=appimage['screenshots']
358                if 'links' in appimage.keys():
359                        if appimage['links']:
360                                for link in appimage['links']:
361                                        if 'url' in link.keys() and link['type']=='Download':
362                                                appinfo['installerUrl']=link['url']
363                if 'authors' in appimage.keys():
364                        if appimage['authors']:
365                                for author in appimage['authors']:
366                                        if 'url' in author.keys():
367                                                #self._debug("Author: %s"%author['url'])
368                                                appinfo['homepage']=author['url']
369                else:
370                        appinfo['homepage']='/'.join(appinfo['installerUrl'].split('/')[0:-1])
371                appinfo['bundle']=['appimage']
372                return appinfo
373        #def load_json_appinfo
374
375        def _th_generate_xml_catalog(self,applist,outdir,info_url,repo,repo_name):
376                maxconnections = 2
377                threads=[]
378                semaphore = threading.BoundedSemaphore(value=maxconnections)
379                random_applist = list(applist)
380                random.shuffle(random_applist)
381                for app in applist:
382                        th=threading.Thread(target=self._th_write_xml, args = (app,outdir,info_url,repo,repo_name,semaphore))
383                        threads.append(th)
384                        th.start()
385                for thread in threads:
386                        thread.join()
387        #def _th_generate_xml_catalog
388
389        def     _th_write_xml(self,appinfo,outdir,info_url,repo,repo_name,semaphore):
390                semaphore.acquire()
391                self._add_appimage(appinfo)
392                semaphore.release()
393        #def _th_write_xml
394
395        def _add_appimage(self,appinfo):
396                #Search in local store for the app
397                sw_new=True
398                app=appstream.App()
399                app_orig=self.store.get_app_by_pkgname(appinfo['name'].lower())
400                if not app_orig:
401                        app_orig=self.store.get_app_by_id(appinfo['name'].lower()+".desktop")
402                if app_orig:
403                        #self._debug("Extending app %s"%appinfo['package'])
404                        if appinfo['icon']:
405                                #self._debug("Icon: %s"%appinfo['icon'])
406                                app=self._copy_app_from_appstream(app_orig,app,copy_icon=False)
407                        else:
408                                app=self._copy_app_from_appstream(app_orig,app,copy_icon=True)
409                        sw_new=False
410                else:
411                        #self._debug("Generating new %s"%appinfo['package'])
412                        pass
413                if appinfo['name'].endswith('.appimage'):
414                        app.set_id("appimagehub.%s"%appinfo['name'].lower())
415                        app.set_name("C",appinfo['name'])
416                else:
417                        app.set_id("appimagehub.%s"%appinfo['name'].lower()+'.appimage')
418                        app.set_name("C",appinfo['name']+".appimage")
419                if appinfo['package'].endswith('.appimage'):
420                        app.add_pkgname(appinfo['package'].lower())
421                else:
422                        app.add_pkgname(appinfo['package'].lower()+".appimage")
423                app.set_id_kind=appstream.IdKind.DESKTOP
424
425                if appinfo['license']:
426                        app.set_project_license(appinfo['license'])
427                bundle=appstream.Bundle()
428                bundle.set_kind(bundle.kind_from_string('APPIMAGE'))
429                if appinfo['package'].endswith('.appimage'):
430                        bundle.set_id(appinfo['package'])
431                else:
432                        bundle.set_id(appinfo['package']+'.appimage')
433                app.add_bundle(bundle)
434                if 'keywords' in appinfo.keys():
435                        for keyword in appinfo['keywords']:
436                                app.add_keyword("C",keyword)
437                        if 'appimage' not in appinfo['keywords']:
438                                app.add_keyword("C","appimage")
439                else:
440                        app.add_keyword("C","appimage")
441                app.add_url(appstream.UrlKind.UNKNOWN,appinfo['installerUrl'])
442                app.add_url(appstream.UrlKind.HOMEPAGE,appinfo['homepage'])
443                if sw_new:
444                        app.add_keyword("C",appinfo['package'])
445                        if not appinfo['name'].endswith('.appimage'):
446                                app.set_name("C",appinfo['name']+".appimage")
447                        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']
448                        if appinfo['description']:
449                                for lang,desc in appinfo['description'].items():
450                                        desc=desc.replace('&','&amp;')
451                                        description="<p>%s</p><p>%s</p>"%(desc_header,desc)
452                                        summary=' '.join(list(desc.split(' ')[:10]))
453                                        app.set_description(lang,description)
454                                        app.set_comment(lang,summary)
455                        else:
456                                description="<p>%s</p>"%(desc_header)
457                                summary=' '.join(list(desc_header.split(' ')[:8]))
458                                app.set_description("C",description)
459                                app.set_comment("C",summary)
460
461                        if 'categories' in appinfo.keys():
462                                for category in appinfo['categories']:
463                                        app.add_category(category)
464                                if 'appimage' not in appinfo['categories']:
465                                        app.add_category("appimage")
466                        else:
467                                app.add_category("appimage")
468                if appinfo['icon']:
469                        icon=appstream.Icon()
470                        if self.icon_cache_enabled:
471                                icon.set_kind(appstream.IconKind.LOCAL)
472                                icon_fn=self._download_file(appinfo['icon'],appinfo['name'],self.icons_dir)
473                                icon.set_filename(icon_fn)
474                        else:
475                                icon.set_kind(appstream.IconKind.REMOTE)
476                                icon.set_name(pkg.get_icon())
477                                icon.set_url(pkg.get_icon())
478                        app.add_icon(icon)
479                if appinfo['thumbnails']:
480                        screenshot=appstream.Screenshot()
481                        img=appstream.Image()
482                        if not appinfo['thumbnails'][0].startswith('http'):
483                                        appinfo['screenshot']=appinfo['thumbnails'][0]
484                                        appinfo['screenshot']="https://appimage.github.io/database/%s"%appinfo['screenshot']
485                        img.set_kind(appstream.ImageKind.SOURCE)
486                        img.set_url(appinfo['screenshot'])
487                        screenshot.add_image(img)
488                        app.add_screenshot(screenshot)
489                #Adds the app to the store
490                self.apps_for_store.put(app)
491                if not os.path.isfile(self.cache_xmls+'/'+app.get_id_filename()):
492                        xml_path='%s/%s.xml'%(self.cache_xmls,app.get_id_filename())
493                        gioFile=Gio.File.new_for_path(xml_path)
494                        app.to_file(gioFile)
495                        #Fix some things in app_file...
496                        xml_file=open(xml_path,'r',encoding='utf-8')
497                        xml_data=xml_file.readlines()
498                        xml_file.close()
499                        #self._debug("fixing %s"%xml_path)
500                        try:
501                                xml_data[0]=xml_data[0]+"<components origin=\"%s\">\n"%app.get_origin()
502                                xml_data[-1]=xml_data[-1]+"\n"+"</components>"
503                        except:
504                                pass
505                        xml_file=open(xml_path,'w')
506                        xml_file.writelines(xml_data)
507                        xml_file.close()
508        #def _add_appimage
509
510        def _copy_app_from_appstream(self,app_orig,app,copy_icon=True):
511                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]
512                app.set_id("appimage."+app_orig.get_id())
513                for category in app_orig.get_categories():
514                        app.add_category(category)
515                app.add_category("appimage")
516                for screenshot in app_orig.get_screenshots():
517                        app.add_screenshot(screenshot)
518                if copy_icon:
519                        for icon in app_orig.get_icons():
520                                app.add_icon(icon)
521                for localeItem in self.locale:
522                        if app_orig.get_name(localeItem):
523                                app.set_name(localeItem,app_orig.get_name(localeItem)+".appimage")
524                        if app_orig.get_description(localeItem):
525                                app.set_description(localeItem,"<p>%s</p><p>%s</p>"%(desc_header,app_orig.get_description(localeItem)))
526                        if app_orig.get_comment(localeItem):
527                                app.set_comment(localeItem,app_orig.get_comment(localeItem))
528                app.set_origin(app_orig.get_origin())
529                return app
530        #def _copy_app_from_appstream
531
532        def _clean_bundle_catalogue(self,applist,outdir):
533                xml_files_list=[]
534                applist=[item.lower() for item in applist]
535                for xml_file in os.listdir(outdir):
536                        if xml_file.endswith('.xml'):
537                                xml_files_list.append(xml_file.lower().replace('.xml','appimage'))
538       
539                if xml_files_list:
540                        xml_discard_list=list(set(xml_files_list).difference(applist))
541                        for discarded_file in xml_discard_list:
542                                os.remove(outdir+'/'+discarded_file.replace('appimage','.xml'))
543        #def _clean_bunlde_catalogue
544
545        def _download_file(self,url,app_name,dest_dir):
546                target_file=dest_dir+'/'+app_name+".png"
547                if not url.startswith('http'):
548                        url="https://appimage.github.io/database/%s"%url
549                if not os.path.isfile(target_file):
550                        if not os.path.isfile(target_file):
551                                #self._debug("Downloading %s to %s"%(url,target_file))
552                                try:
553                                        with urllib.request.urlopen(url) as response, open(target_file, 'wb') as out_file:
554                                                bf=16*1024
555                                                acumbf=0
556                                                file_size=int(response.info()['Content-Length'])
557                                                while True:
558                                                        if acumbf>=file_size:
559                                                            break
560                                                        shutil.copyfileobj(response, out_file,bf)
561                                                        acumbf=acumbf+bf
562                                        st = os.stat(target_file)
563                                except Exception as e:
564                                        #self._debug("Unable to download %s"%url)
565                                        #self._debug("Reason: %s"%e)
566                                        target_file=''
567                return(target_file)
568        #def _download_file
569       
570        def _chk_bundle_dir(self,outdir):
571                msg_status=True
572                if not os.path.isdir(outdir):
573                        try:
574                                os.makedirs(outdir)
575                        except Exception as e:
576                                msg_status=False
577                                print(e)
578                return(os.access(outdir,os.W_OK|os.R_OK|os.X_OK|os.F_OK))
579        #def _chk_bundle_dir
580       
581        def _init_appinfo(self):
582                appInfo={'appstream_id':'',\
583                'id':'',\
584                'name':'',\
585                'version':'',\
586                'channel_releases':{},\
587                'component':'',\
588                'package':'',\
589                'license':'',\
590                'summary':'',\
591                'description':{},\
592                'categories':[],\
593                'icon':'',\
594                'screenshot':'',\
595                'thumbnails':[],\
596                'video':'',\
597                'homepage':'',\
598                'installerUrl':'',\
599                'state':'',\
600                'depends':'',\
601                'kudos':'',\
602                'suggests':'',\
603                'extraInfo':'',\
604                'size':'',\
605                'bundle':'',\
606                'updatable':'',\
607                }
608                return(appInfo)
609        #def _init_appinfo
610       
611        def _get_info(self,app_info,force=False):
612                #self._debug("Searching for %s in %s"%(app_info['package'],self.appimage_dir))
613                app_info['state']='available'
614                if os.path.isfile(self.appimage_dir+'/'+app_info['package']):
615                        app_info['state']='installed'
616                if not app_info['size'] or force:
617                        if app_info['installerUrl']:
618                                #self._debug("installer: %s"%app_info['installerUrl'])
619                                app_info['channel_releases']={'appimage':[]}
620                                app_info['channel_releases']['appimage']=self._get_releases(app_info)
621                        #Get size
622                        app_info['size']=0
623                        app_info['version']='unknown'
624                        if 'appimage' in app_info['channel_releases'].keys():
625                                if len(app_info['channel_releases']['appimage'])>0:
626                                        if app_info['channel_releases']['appimage'][0]:
627                                                appimage_url=app_info['channel_releases']['appimage'][0]
628                                                dest_path=self.appimage_dir+'/'+app_info['package']
629                                                if appimage_url:
630                                                        try:
631                                                                with urllib.request.urlopen(appimage_url) as response:
632                                                                        app_info['size']=(response.info()['Content-Length'])
633                                                        except:
634                                                                app_info['size']=0
635                                        #Version (unaccurate aprox)
636                                        app_info['version']=app_info['channel_releases']['appimage'][0].split('/')[-2]
637
638                self._set_status(0)
639                self.partial_progress=100
640                return(app_info)
641        #def _get_info
642
643        def _get_releases(self,app_info):
644                releases=[]
645                releases_page=''
646                #self._debug("Info url: %s"%app_info['installerUrl'])
647                url_source=""
648                try:
649                        if 'github' in app_info['installerUrl']:
650                                releases_page="https://github.com"
651                        if 'gitlab' in app_info['installerUrl']:
652                                releases_page="https://gitlab.com"
653                        if 'opensuse' in app_info['installerUrl'].lower():
654                                releases_page=""
655                                url_source="opensuse"
656#                               app_info['installerUrl']=app_info['installerUrl']+"/download"
657
658                        if url_source or releases_page:
659                                with urllib.request.urlopen(app_info['installerUrl']) as f:
660                                        content=(f.read().decode('utf-8'))
661                                        soup=BeautifulSoup(content,"html.parser")
662                                        package_a=soup.findAll('a', attrs={ "href" : re.compile(r'.*\.[aA]pp[iI]mage$')})
663
664                                        for package_data in package_a:
665                                                if url_source=="opensuse":
666                                                        package_name=package_data.findAll('a', attrs={"class" : "mirrorbrain-btn"})
667                                                else:
668                                                        package_name=package_data.findAll('strong', attrs={ "class" : "pl-1"})
669                                                package_link=package_data['href']
670                                                if releases_page or url_source:
671                                                        package_link=releases_page+package_link
672                                                        releases.append(package_link)
673                                                        #self._debug("Link: %s"%package_link)
674                        else:
675                                releases=[app_info['installerUrl']]
676                except Exception as e:
677                        print(e)
678                #self._debug(releases)
679                return releases
680        #def _get_releases
681       
Note: See TracBrowser for help on using the repository browser.