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

Last change on this file since 7137 was 7137, checked in by Juanma, 22 months ago

WIP on releases

File size: 23.3 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=True
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.conf_dir=os.getenv("HOME")+"/.cache/lliurex-store"
31                self.icons_dir=self.conf_dir+"/icons"
32                self.bundles_dir=self.conf_dir+"/bundles"
33                self.bundle_types=['appimg']
34                self.appimage_dir=os.getenv("HOME")+"/.lliurex-store/appimg"
35                #To get the description of an app we must go to a specific url defined in url_info.
36                #$(appname) we'll be replaced with the appname so the url matches the right one.
37                #If other site has other url naming convention it'll be mandatory to define it with the appropiate replacements
38                self.repos={'appimagehub':{'type':'json','url':'https://appimage.github.io/feed.json','url_info':''}}
39                #Appimges not stored in a repo must be listed in this file, providing the download url and the info url (if there's any)
40                self.external_appimages="/usr/share/lliurex-store/files/external_appimages.json"
41                #Queue pool
42                self.queue=queue.Queue()
43                self.disabled=False
44        #def __init__
45
46        def set_debug(self,dbg=True):
47                self.dbg=dbg
48                self._debug ("Debug enabled")
49        #def set_debug
50
51        def _debug(self,msg=''):
52                if self.dbg:
53                        print ('DEBUG appimage: %s'%msg)
54        #def debug
55
56        def register(self):
57                return(self.plugin_actions)
58
59        def enable(self,state=False):
60                self.disable=state
61
62        def execute_action(self,action,applist=None,store=None):
63                if store:
64                        self.store=store
65                else:
66                        self.store=appstream.Store()
67                self.progress=0
68                self.result['status']={'status':-1,'msg':''}
69                self.result['data']=''
70                dataList=[]
71                if self.disabled:
72                        self._set_status(9)
73                        self.result['data']=self.store
74                else:
75                        self._chk_installDir()
76                        if action=='load':
77                                self.result['data']=self._load_appimage_store()
78                        else:
79                                for app_info in applist:
80                                        self.partial_progress=0
81                                        if action=='install':
82                                                dataList.append(self._install_appimage(app_info))
83                                        if action=='remove':
84                                                dataList.append(self._remove_appimage(app_info))
85                                        if action=='pkginfo':
86                                                dataList.append(self._get_info(app_info))
87                                        self.progress+=int(self.partial_progress/len(applist))
88                                self.result['data']=list(dataList)
89                self.progress=100
90                return(self.result)
91
92        def _set_status(self,status,msg=''):
93                self.result['status']={'status':status,'msg':msg}
94        #def _set_status
95
96        def _callback(self,partial_size=0,total_size=0):
97                limit=99
98                if partial_size!=0 and total_size!=0:
99                        inc=round(partial_size/total_size,2)*100
100                        self.progress=inc
101                else:
102                        inc=1
103                        margin=limit-self.progress
104                        inc=round(margin/limit,3)
105                        self.progress=(self.progress+inc)
106                if (self.progress>limit):
107                        self.progress=limit
108
109        def _chk_installDir(self):
110                msg_status=True
111                if not os.path.isdir(self.appimage_dir):
112                        try:
113                                os.makedirs(self.appimage_dir)
114                        except:
115                                msg_status=False
116                return msg_status                               
117
118        def _install_appimage(self,app_info):
119                app_info=self._get_info(app_info)
120                self._debug("Installing %s"%app_info)
121                if app_info['state']=='installed':
122                        self._set_status(4)
123                else:
124                                #                       appimage_url=self.repository_url+'/'+app_info['package']
125                        appimage_url=app_info['homepage']+'/'+app_info['package']
126                        self._debug("Downloading "+appimage_url)
127                        dest_path=self.appimage_dir+'/'+app_info['package']
128                        if appimage_url:
129                                try:
130                                        req=Request(appimage_url, headers={'User-Agent':'Mozilla/5.0'})
131                                        with urllib.request.urlopen(req) as response, open(dest_path, 'wb') as out_file:
132                                                bf=16*1024
133                                                acumbf=0
134#                                               print("Response: %s"%response.info())
135                                                app_size=int(response.info()['Content-Length'])
136#                                               print("APP SIZE: %s"%app_size)
137                                                while True:
138                                                        if acumbf>=app_size:
139                                                            break
140                                                        shutil.copyfileobj(response, out_file,bf)
141                                                        acumbf=acumbf+bf
142                                                        self._callback(acumbf,app_size)
143                                        st = os.stat(dest_path)
144                                        os.chmod(dest_path, st.st_mode | 0o111)
145                                        self._set_status(0)
146                                except Exception as e:
147                                        print(e)
148                                        self._set_status(5)
149                        else:
150                                self._set_status(12)
151                return app_info
152        #def _install_appimage
153
154        def _remove_appimage(self,app_info):
155                self._debug("Removing "+app_info['package'])
156                if os.path.isfile(self.appimage_dir+'/'+app_info['package']):
157                        try:
158                                call([self.appimage_dir+"/"+app_info['package'], "--remove-appimage-desktop-integration"])
159                        except:
160                                pass
161                        try:
162                                os.remove(self.appimage_dir+"/"+app_info['package'])
163                                self._set_status(0)
164                        except:
165                                self._set_status(6)
166                return(app_info)
167        #def _remove_appimage
168
169        def _load_appimage_store(self,store=None):
170                self._get_bundles_catalogue()
171                if os.path.exists(self.bundles_dir):
172                        for bundle_type in self.bundle_types:
173                                self._debug("Loading %s catalog"%bundle_type)
174                                store=self._generic_file_load(self.bundles_dir+'/'+bundle_type,store)
175                return(store)
176        #def load_bundles_catalog(self)
177       
178        def _generic_file_load(self,target_path,store):
179                icon_path='/usr/share/icons/hicolor/128x128'
180                if not os.path.isdir(target_path):
181                        os.makedirs(target_path)
182                files=os.listdir(target_path)
183                for target_file in os.listdir(target_path):
184                        if target_file.endswith('appdata.xml'):
185                                store_path=Gio.File.new_for_path(target_path+'/'+target_file)
186                                self._debug("Adding file "+target_path+'/'+target_file)
187                                try:
188                                        store.from_file(store_path,icon_path,None)
189                                except Exception as e:
190                                        self._debug("Couldn't add file "+target_file+" to store")
191                                        self._debug("Reason: "+str(e))
192                return(store)
193        #def _generic_file_load
194
195        def _get_bundles_catalogue(self):
196                applist=[]
197                appdict={}
198                all_apps=[]
199                outdir=self.bundles_dir+'/appimg/'
200                #Load repos
201                for repo_name,repo_info in self.repos.items():
202                        if not os.path.isdir(self.bundles_dir):
203                                try:
204                                        os.makedirs(self.bundles_dir)
205                                except:
206                                        self._debug("appImage catalogue could not be fetched: Permission denied")
207                        self._debug("Fetching repo %s"%repo_info['url'])
208                        if repo_info['type']=='json':
209                                applist=self._process_appimage_json(self._fetch_repo(repo_info['url']),repo_name)
210
211                        self._debug("Fetched repo "+repo_info['url'])
212                        self._th_generate_xml_catalog(applist,outdir,repo_info['url_info'],repo_info['url'],repo_name)
213                        all_apps.extend(applist)
214                #Load external apps
215                for app_name,app_info in self._get_external_appimages().items():
216                        if os.path.isdir(self.bundles_dir):
217                                appinfo=self._init_appinfo()
218                                appinfo['name']=app_info['url'].split('/')[-1]
219                                appinfo['package']=app_info['url'].split('/')[-1]
220                                appinfo['homepage']='/'.join(app_info['url'].split('/')[0:-1])
221                                self._debug("Fetching external appimage %s"%app_info['url'])
222                                appinfo['bundle']='appimage'
223                                applist=[appinfo]
224                                self._th_generate_xml_catalog(applist,outdir,app_info['url_info'],app_info['url'],app_name)
225                                self._debug("Fetched appimage "+app_info['url'])
226                                all_apps.extend(applist)
227                        else:
228                                self._debug("External appImage could not be fetched: Permission denied")
229                self._debug("Removing old entries...")
230#               self._clean_bundle_catalogue(all_apps,outdir)
231                return(True)
232        #def _get_bundles_catalogue
233       
234        def _fetch_repo(self,repo):
235                req=Request(repo, headers={'User-Agent':'Mozilla/5.0'})
236                with urllib.request.urlopen(req) as f:
237                        content=(f.read().decode('utf-8'))
238               
239                return(content)
240        #def _fetch_repo
241       
242        def _get_external_appimages(self):
243                external_appimages={}
244                if os.path.isfile(self.external_appimages):
245                        try:
246                                with open(self.external_appimages) as appimages:
247                                        external_appimages=json.load(appimages)
248                        except:
249                                self._debug("Can't load %s"%self.external_appimages)
250                self._debug(external_appimages)
251                return external_appimages
252        #def _get_external_appimages
253       
254        def _process_appimage_json(self,data,repo_name):
255                maxconnections = 10
256                semaphore = threading.BoundedSemaphore(value=maxconnections)
257                applist=[]
258                json_data=json.loads(data)
259                if 'items' in json_data.keys():
260                        for appimage in json_data['items']:
261                                appinfo=self._th_process_appimage(appimage,semaphore)
262                                if appinfo:
263                                        applist.append(appinfo)
264                                        #                               th=threading.Thread(target=self._th_process_appimage, args = (appimage,semaphore))
265#                               th.start()
266
267#               while threading.active_count()>1:
268#                       print("%s"%threading.active_count())
269#                       time.sleep(0.1)
270
271#               while not self.queue.empty():
272#                       applist.append(self.queue.get())
273#                       self._debug("Added %s"%applist[-1])
274#               self._debug("JSON: %s"%applist)
275                return (applist)
276        #_process_appimage_json
277
278        def _th_process_appimage(self,appimage,semaphore):
279                appinfo=None
280#               semaphore.acquire()
281#               lock=threading.Lock()
282                releases=[]
283                if 'links' in appimage.keys():
284                        if appimage['links']:
285                                appinfo=self.load_json_appinfo(appimage)
286#Deprecated. appImage releases will be load on the info stage
287#                       releases=self._get_releases_from_json(appimage)
288#                       if releases:
289#                               appinfo['releases']=releases
290#                               for release in releases:
291#                                       #Release has the direct download url
292#                                       tmp_release=release.split('/')
293#                                       tmp_appinfo=appinfo.copy()
294#                                       rel_number=tmp_release[-2]
295#                                       rel_name=tmp_release[-1].lower().replace('.appimage','')
296#                                       self._debug("Release: %s"%release)
297#                                       tmp_appinfo['name']=rel_name
298#                                       tmp_appinfo['package']=tmp_release[-1]
299#                                       tmp_appinfo['homepage']='/'.join(tmp_release[0:-1])
300#                                       self.queue.put(tmp_appinfo)
301#Threading disabled
302#                               self.queue.put(appinfo)
303                return(appinfo)
304        #def _th_process_appimage
305
306        def load_json_appinfo(self,appimage):
307                appinfo=self._init_appinfo()
308                appinfo['name']=appimage['name']
309                appinfo['package']=appimage['name']
310                if 'license' in appimage.keys():
311                        appinfo['license']=appimage['license']
312                appinfo['summary']=''
313                if 'description' in appimage.keys():
314                        appinfo['description']=appimage['description']
315                if 'categories' in appimage.keys():
316                        appinfo['categories']=appimage['categories']
317                if 'icon' in appimage.keys():
318                        appinfo['icon']=appimage['icon']
319                if 'screenshots' in appimage.keys():
320                        appinfo['thumbnails']=appimage['screenshots']
321                if 'links' in appimage.keys():
322                        if appimage['links']:
323                                for link in appimage['links']:
324                                        if 'url' in link.keys() and link['type']=='Download':
325                                                appinfo['homepage']=link['url']
326                elif 'authors' in appimage.keys():
327                        if appimage['authors']:
328                                for author in appimage['authors']:
329                                        if 'url' in author.keys():
330                                                appinfo['homepage']=author['url']
331                appinfo['bundle']=['appimage']
332                return appinfo
333        #def load_json_appinfo
334
335        def _th_generate_xml_catalog(self,applist,outdir,info_url,repo,repo_name):
336                maxconnections = 10
337                semaphore = threading.BoundedSemaphore(value=maxconnections)
338                random_applist = list(applist)
339                random.shuffle(random_applist)
340                for app in applist:
341                        th=threading.Thread(target=self._th_write_xml, args = (app,outdir,info_url,repo,repo_name,semaphore))
342                        th.start()
343        #def _th_generate_xml_catalog
344
345        def _th_write_xml(self,appinfo,outdir,info_url,repo,repo_name,semaphore):
346                semaphore.acquire()
347                lock=threading.Lock()
348#               self._debug("Populating %s"%appinfo)
349                package=appinfo['name'].lower().replace(".appimage","")
350                if len(package)>40:
351                        tmp_package=package.split('-')
352                        tam=0
353                        pos=1
354                        index=0
355                        banned=['linux32','linux64','i386','x86_64','ia32','amd64']
356                        for tmp_name in tmp_package:
357                                if (tam<len(tmp_name) and pos<index) and tmp_name not in banned:
358                                        tam=len(tmp_name)
359                                        pos=index
360                                index+=1
361                        print("Removed: %s"%tmp_package[pos])
362                        tmp_package[pos]=''
363                        package='-'.join(tmp_package)
364                        package=package.replace("--","-")
365                        package=package.replace("-.",".")
366
367#               filename=outdir+package.lower().replace('appimage',"appdata")+".xml"
368#               self._debug("checking if we need to download "+filename)
369#               if not os.path.isfile(filename):
370                repo_info={'info_url':info_url,'repo':repo,repo_name:'repo_name'}
371                self._write_xml_file(appinfo,repo_info,lock)
372                semaphore.release()
373        #def _th_write_xml
374
375        def _write_xml_file(self,appinfo,repo_info,lock):
376                #Search in local store for the app
377                sw_new=False
378                app=self.store.get_app_by_pkgname(appinfo['package'].lower())
379                if not app:
380                        self._debug("Searching for %s"%appinfo['package'])
381                        app=self.store.get_app_by_id(appinfo['package'].lower()+".desktop")
382                if not app:
383                        self._debug("Generating new %s"%appinfo['package'])
384                        app=appstream.App()
385                        sw_new=True
386                bundle=appstream.Bundle()
387                icon=appstream.Icon()
388                screenshot=appstream.Screenshot()
389                #F*****g appstream have kinds undefined but kind_from_string works... wtf?
390#               bundle.set_kind(appstream.BundleKind.SNAP)
391                bundle.set_kind(bundle.kind_from_string('APPIMAGE'))
392                bundle.set_id(appinfo['package']+'.appimage')
393                app.add_bundle(bundle)
394                app.add_keyword("C","appimage")
395                app.add_category("appimage")
396                app.add_pkgname(appinfo['package'].lower()+".appimage")
397                app.add_url(appstream.UrlKind.UNKNOWN,appinfo['homepage'])
398                if sw_new:
399                        app.set_name("C",appinfo['name'])
400#               app.add_pkgname(pkg.get_name()+'.snap')
401                        app.add_pkgname(appinfo['package'].lower()+".appimage")
402#               release=appstream.Release()
403#               release.set_version(pkg.get_version())
404#               app.add_release(release)
405                        app.set_id("appimagehub.%s"%appinfo['name'].lower()+'.appimage')
406#               app.set_id(pkg.get_name()+'.snap')
407                        app.set_id_kind=appstream.IdKind.DESKTOP
408                        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'],appinfo['description'])
409                        summary=' '.join(list(description.split(' ')[:8]))
410                        if len(description.split(' '))>8:
411                                summary+="... "
412                        app.set_description("C",description)
413                        app.set_comment("C",summary)
414                        for category in appinfo['categories']:
415                                app.add_category(category)
416                        self.store.add_app(app)
417
418#               app.add_keyword("C",pkg.get_name())
419#               for word in pkg.get_summary().split(' '):
420#                       app.add_keyword("C",word)
421
422#               if pkg.get_icon():
423#                       if self.icon_cache_enabled:
424#                               icon.set_kind(appstream.IconKind.LOCAL)
425#                               icon.set_name(self._download_file(pkg.get_icon(),pkg.get_name(),self.icons_folder))
426#                       else:
427#                               icon.set_kind(appstream.IconKind.REMOTE)
428#                               icon.set_name(pkg.get_icon())
429#                       app.add_icon(icon)
430
431#               if pkg.get_license():
432#                       app.set_project_license(pkg.get_license())
433
434#               if pkg.get_screenshots():
435#                       for snap_screen in pkg.get_screenshots():
436#                               img=appstream.Image()
437##                              img.load_filename(self._download_file(snap_screen.get_url(),pkg.get_name(),self.images_folder))
438#                               img.set_kind(appstream.ImageKind.SOURCE)
439#                               img.set_url(snap_screen.get_url())
440#                               break
441#                       screenshot.add_image(img)
442#                       app.add_screenshot(screenshot)
443                return(app)
444#                       name=appinfo['name'].lower().replace(".appimage","")
445#                       self._debug("Generating %s xml"%appinfo['package'])
446#                       f=open(filename,'w')
447#                       f.write('<?xml version="1.0" encoding="UTF-8"?>'+"\n")
448#                       f.write("<components version=\"0.10\">\n")
449#                       f.write("<component  type=\"desktop-application\">\n")
450#                       f.write("  <id>%s</id>\n"%appinfo['package'].lower())
451#                       f.write("  <pkgname>%s</pkgname>\n"%appinfo['package'])
452#                       f.write("  <name>%s</name>\n"%name)
453#                       f.write("  <metadata_license>CC0-1.0</metadata_license>\n")
454#                       f.write("  <provides><binary>%s</binary></provides>\n"%appinfo['package'])
455#                       if 'releases' in appinfo.keys():
456#                               f.write("  <releases>\n")
457#                               for release in appinfo['releases']:
458#                                       tmp_release=release.split('/')
459#                                       rel_number='/'.join(tmp_release[-2:])
460#                                       f.write("    <release version=\"%s\" urgency=\"medium\">"%rel_number)
461#                                       f.write("</release>\n")
462#                               f.write("  </releases>\n")
463#                       f.write("  <launchable type=\"desktop-id\">%s.desktop</launchable>\n"%name)
464#                       if appinfo['description']=='':
465#                               with lock:
466#                                       try:
467#                                               if appinfo['name'] in self.descriptions_dict.keys():
468#                                                       (description,icon)=self.descriptions_dict[appinfo['name']]
469#                                               else:
470#                                                       (description,icon)=self._get_description_icon(appinfo['name'],repo_info)
471#                                                       self.descriptions_dict.update({appinfo['name']:[description,icon]})
472#                                       except:
473#                                               description=''
474#                                               icon=''
475#                       else:
476#                               description=appinfo['description']
477#                       summary=' '.join(list(description.split(' ')[:8]))
478#                       if len(description.split(' '))>8:
479#                               summary+="... "
480#                       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"%(name,description)
481#                       if summary=='':
482#                               summary=' '.join(list(description.split(' ')[:8]))
483#                       f.write("  <description><p></p><p>%s</p></description>\n"%description)
484#                       f.write("  <summary>%s</summary>\n"%summary)
485##                      f.write("  <icon type=\"local\">%s</icon>\n"%appinfo['icon'])
486#                       f.write("<icon type=\"cached\">"+name+"_"+name+".png</icon>\n")
487#                       f.write("  <url type=\"homepage\">%s</url>\n"%appinfo['homepage'])
488#                       f.write("  <bundle type=\"appimage\">%s</bundle>\n"%appinfo['name'])
489#                       f.write("  <keywords>\n")
490#                       keywords=name.split("-")
491#                       banned_keywords=["linux","x86_64","i386","ia32","amd64"]
492#                       for keyword in keywords:
493#                               #Better than isalpha method for this purpose
494#                               if keyword.isidentifier() and keyword not in banned_keywords:
495#                                       f.write("       <keyword>%s</keyword>\n"%keyword)
496#                       f.write("       <keyword>appimage</keyword>\n")
497#                       f.write("  </keywords>\n")
498#                       f.write("  <categories>\n")
499#                       f.write("       <category>AppImage</category>\n")
500#                       if 'categories' in appinfo.keys():
501#                               for category in appinfo['categories']:
502#                                       f.write("       <category>%s</category>\n"%category)
503#                       f.write("  </categories>\n")
504#                       f.write("</component>\n")
505#                       f.write("</components>\n")
506#                       f.close()
507        #def _write_xml_file
508
509        def _get_description_icon(self,app_name,info_url,repo_name):
510                desc=''
511                icon=''
512                if info_url:
513                        if '$(appname)' in info_url:
514                                info_url=info_url.replace('$(appname)',app_name)
515                        self._debug("Getting description from repo/app %s - %s "%(repo_name,info_url))
516                        try:
517                                with urllib.request.urlopen(info_url) as f:
518                                        if repo_name=='probono':
519                                                content=(f.read().decode('utf-8'))
520                                                soup=BeautifulSoup(content,"html.parser")
521                                                description_div=soup.findAll('div', attrs={ "class" : "description-text"})
522                                                icon_div=soup.findAll('div', attrs={ "class" : "avatar-icon avatar-large description-icon "})
523                                if len(description_div)>0:
524                                        desc=description_div[0].text
525                                        desc=desc.replace(':','.')
526                                        desc=desc.replace('&','&amp;')
527                                if len(icon_div)>0:
528                                        icon_str=str(icon_div[0])
529                                        icon=icon_str.split(' ')[9]
530                                        icon=icon.lstrip('url(')
531                                        if icon.startswith('http'):
532                                                icon=icon.rstrip(');"></div>')
533                                                icon=self._download_file(icon,app_name)
534                                        print("Icon: %s"%icon)
535                        except Exception as e:
536                                print("Can't get description from "+info_url)
537                                print(str(e))
538                                pass
539                return([desc,icon])
540        #def _get_description
541
542        def _clean_bundle_catalogue(self,applist,outdir):
543                xml_files_list=[]
544                applist=[item.lower() for item in applist]
545                for xml_file in os.listdir(outdir):
546                        if xml_file.endswith('appdata.xml'):
547                                xml_files_list.append(xml_file.lower().replace('appdata.xml','appimage'))
548       
549                if xml_files_list:
550                        xml_discard_list=list(set(xml_files_list).difference(applist))
551                        for discarded_file in xml_discard_list:
552                                os.remove(outdir+'/'+discarded_file.replace('appimage','appdata.xml'))
553        #def _clean_bunlde_catalogue
554
555        def _download_file(self,url,app_name):
556#               target_file=self.icons_folder+'/'+app_name+".png"
557                target_file=self.icons_dir+'/'+app_name+".png"
558                if not os.path.isfile(target_file):
559#                       shutil.copy("/usr/share/icons/hicolor/128x128/apps/lliurex-store.png",target_file)
560#                       if not os.fork():
561                        if not os.path.isfile(target_file):
562                                self._debug("Downloading %s to %s"%(url,target_file))
563                                try:
564                                        with urllib.request.urlopen(url) as response, open(target_file, 'wb') as out_file:
565                                                bf=16*1024
566                                                acumbf=0
567                                                file_size=int(response.info()['Content-Length'])
568                                                while True:
569                                                        if acumbf>=file_size:
570                                                            break
571                                                        shutil.copyfileobj(response, out_file,bf)
572                                                        acumbf=acumbf+bf
573                                        st = os.stat(target_file)
574                                except Exception as e:
575                                        self._debug("Unable to download %s"%url)
576                                        self._debug("Reason: %s"%e)
577                                        target_file=url
578#                               os._exit(0)
579                return(target_file)
580        #def _download_file
581       
582        def _chk_bundle_dir(self,outdir):
583                msg_status=True
584                if not os.path.isdir(outdir):
585                        try:
586                                os.makedirs(outdir)
587                        except Exception as e:
588                                msg_status=False
589                                print(e)
590                return(os.access(outdir,os.W_OK|os.R_OK|os.X_OK|os.F_OK))
591        #def _chk_bundle_dir
592       
593        def _init_appinfo(self):
594                appInfo={'appstream_id':'',\
595                'id':'',\
596                'name':'',\
597                'version':'',\
598                'releases':[],\
599                'package':'',\
600                'license':'',\
601                'summary':'',\
602                'description':'',\
603                'categories':[],\
604                'icon':'',\
605                'screenshot':'',\
606                'thumbnails':[],\
607                'video':'',\
608                'homepage':'',\
609                'installerUrl':'',\
610                'state':'',\
611                'depends':'',\
612                'kudos':'',\
613                'suggests':'',\
614                'extraInfo':'',\
615                'size':'',\
616                'bundle':'',\
617                'updatable':'',\
618                }
619                return(appInfo)
620        #def _init_appinfo
621       
622        def _get_info(self,app_info):
623                app_info=self._get_releases(app_info)
624                app_info['state']='available'
625                if os.path.isfile(self.appimage_dir+'/'+app_info['package']):
626                        app_info['state']='installed'
627                #Get size
628                appimage_url=app_info['homepage']+'/'+app_info['package']
629                dest_path=self.appimage_dir+'/'+app_info['package']
630                if appimage_url:
631                        try:
632                                with urllib.request.urlopen(appimage_url) as response:
633                                        app_info['size']=(response.info()['Content-Length'])
634                        except:
635                                app_info['size']=0
636                self._set_status(0)
637                self.partial_progress=100
638                return(app_info)
639        #def _get_info
640
641        def _get_releases(self,app_info):
642                releases=[]
643                if app_info['installerUrl']:
644                        self._debug("Info url: %s"%app_info['installerUrl'])
645                        try:
646                                sw_git=False
647                                if 'github' in app_info['installerUrl']:
648                                        sw_git=True
649#                                       app_info['installerUrl']=app_info['installerUrl']+"/download"
650
651                                with urllib.request.urlopen(app_info['installerUrl']) as f:
652                                        content=(f.read().decode('utf-8'))
653                                        soup=BeautifulSoup(content,"html.parser")
654                                        package_a=soup.findAll('a', attrs={ "href" : re.compile(r'.*\.[aA]pp[iI]mage$')})
655                                        for package_data in package_a:
656                                                package_name=package_data.findAll('strong', attrs={ "class" : "pl-1"})
657                                                package_link=package_data['href']
658                                                if sw_git:
659                                                        package_link="https://github.com"+package_link
660                                                        releases.append(package_link)
661                                                        self._debug("Link: %s"%package_link)
662                        except Exception as e:
663                                print(e)
664                app_info['releases']=releases
665                return app_info
666        #def _get_releases
667       
668        def _get_releases_from_json(self,appimage):
669                releases=[]
670                if appimage['links']:
671                        for link in appimage['links']:
672                                if 'type' in link.keys():
673                                        if link['type']=='Download':
674                                                self._debug("Info url: %s"%link['url'])
675                                                try:
676                                                        sw_git=False
677                                                        with urllib.request.urlopen(link['url']) as f:
678                                                                if 'github' in link['url']:
679                                                                        sw_git=True
680                                                                content=(f.read().decode('utf-8'))
681                                                                soup=BeautifulSoup(content,"html.parser")
682                                                                package_a=soup.findAll('a', attrs={ "href" : re.compile(r'.*[aA]pp[iI]mage$')})
683                                                                for package_data in package_a:
684                                                                        package_name=package_data.findAll('strong', attrs={ "class" : "pl-1"})
685                                                                        package_link=package_data['href']
686                                                                        if sw_git:
687                                                                                package_link="https://github.com"+package_link
688                                                                                releases.append(package_link)
689                                                                                self._debug("Link: %s"%package_link)
690                                                except Exception as e:
691                                                        print(e)
692                return releases
693        #def _get_releases_from_json
694
Note: See TracBrowser for help on using the repository browser.