Advertisement
Guest User

pikinin

a guest
Apr 22nd, 2012
143
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 18.04 KB | None | 0 0
  1. # -*- coding: utf-8 -*-
  2.  
  3. import urllib, urllib2, httplib
  4.  
  5. import re, sys, os, cgi
  6.  
  7. import xbmcplugin, xbmcgui, xbmcaddon, xbmc, gui
  8.  
  9. import threading
  10.  
  11. import simplejson as json
  12.  
  13.  
  14.  
  15. __scriptID__   = sys.modules[ "__main__" ].__scriptID__
  16.  
  17. t = sys.modules[ "__main__" ].__language__
  18.  
  19. __addon__ = xbmcaddon.Addon(__scriptID__)
  20.  
  21.  
  22.  
  23. os.path.join( __addon__.getAddonInfo('path'), "resources" )
  24.  
  25.  
  26.  
  27.  
  28.  
  29.  
  30.  
  31.  
  32.  
  33.  
  34.  
  35.  
  36.  
  37. login = __addon__.getSetting('username')
  38.  
  39. password = __addon__.getSetting('userpassword')
  40.  
  41. multi = __addon__.getSetting('video_quality')
  42.  
  43. display = __addon__.getSetting('list_display')
  44.  
  45.  
  46.  
  47. #confluence: thumb: 500, biglist: 51, normal 50
  48.  
  49. #transparency: thumb: 53, biglist: 52, normal: 590
  50.  
  51.  
  52.  
  53. SKINS = {
  54.  
  55.         'confluence': { 'opt1': 51, 'opt2': 50 },
  56.  
  57.         'transparency': { 'opt1': 52, 'opt2': 590 }
  58.  
  59. }
  60.  
  61.  
  62.  
  63. class Settings:
  64.  
  65.     def __init__(self):
  66.  
  67.         pass
  68.  
  69.  
  70.  
  71.     def showSettings(self):
  72.  
  73.         __addon__.openSettings(sys.argv[0])
  74.  
  75.  
  76.  
  77.     def setApiUrl(self):
  78.  
  79.         return apiUrl
  80.  
  81.  
  82.  
  83.     def setIconUrl(self):
  84.  
  85.         return iconUrl
  86.  
  87.  
  88.  
  89.     def setViewMode(self, view):
  90.  
  91.         if view != 'orig':
  92.  
  93.             for k,v in SKINS.items():
  94.  
  95.                 if k in xbmc.getSkinDir():
  96.  
  97.                     if view == 'general':
  98.  
  99.                         xbmc.executebuiltin("Container.SetViewMode(" + str(v['opt2']) + ")")
  100.  
  101.                     elif view == 'other':
  102.  
  103.                         xbmc.executebuiltin("Container.SetViewMode(" + str(v['opt1']) + ")")
  104.  
  105.  
  106.  
  107.  
  108.  
  109. class ShowList:
  110.  
  111.     def __init__(self):
  112.  
  113.         pass
  114.  
  115.  
  116.  
  117.     def decode(self, string):
  118.  
  119.         json_ustr = json.dumps(string, ensure_ascii=False)
  120.  
  121.         return json_ustr.encode('utf-8')
  122.  
  123.  
  124.  
  125.     def JsonToSortedTab(self, json):
  126.  
  127.         strTab = []
  128.  
  129.         outTab = []
  130.  
  131.         for v,k in json.iteritems():
  132.  
  133.             strTab.append(int(v))
  134.  
  135.             strTab.append(k)
  136.  
  137.             outTab.append(strTab)
  138.  
  139.             strTab = []
  140.  
  141.         outTab.sort(key=lambda x: x[0])
  142.  
  143.         return outTab
  144.  
  145.  
  146.  
  147.     def getJsonFromAPI(self, url):
  148.  
  149.         s = Settings()
  150.  
  151.         result_json = { "0": "Null" }
  152.  
  153.         try:
  154.  
  155.             headers = { 'User-Agent' : HOST, 'ContentType' : 'application/x-www-form-urlencoded' }
  156.  
  157.             post = { 'username': login, 'userpassword': password }
  158.  
  159.             data = urllib.urlencode(post)
  160.  
  161.             reqUrl = urllib2.Request(url, data, headers)
  162.  
  163.             raw_json = urllib2.urlopen(reqUrl)
  164.  
  165.             content_json = raw_json.read()
  166.  
  167.             result_json = json.loads(content_json)
  168.  
  169.         except urllib2.URLError, urlerr:
  170.  
  171.             msg = Messages()
  172.  
  173.             result_json = { "0": "Error" }
  174.  
  175.             print urlerr
  176.  
  177.             msg.Error(t(57001).encode('utf-8'), t(57002).encode('utf-8'), t(57003).encode('utf-8'))
  178.  
  179.         except NameError, namerr:
  180.  
  181.             msg = Messages()
  182.  
  183.             result_json = { "0": "Error" }
  184.  
  185.             print namerr
  186.  
  187.             msg.Error(t(57009).encode('utf-8'), t(57010).encode('utf-8'))
  188.  
  189.         except ValueError, valerr:
  190.  
  191.             msg = Messages()
  192.  
  193.             result_json = { "0": "Error" }
  194.  
  195.             print valerr
  196.  
  197.             msg.Error(t(57001).encode('utf-8'), t(57011).encode('utf-8'), t(57012).encode('utf-8'), t(57013).encode('utf-8'))
  198.  
  199.         except httplib.BadStatusLine, statuserr:
  200.  
  201.             msg = Messages()
  202.  
  203.             result_json = { "0": "Error" }
  204.  
  205.             print statuserr
  206.  
  207.             msg.Error(t(57001).encode('utf-8'), t(57002).encode('utf-8'), t(57003).encode('utf-8'))                                            
  208.  
  209.         return result_json
  210.  
  211.  
  212.  
  213.     def loadChannels(self, url):
  214.  
  215.         action = 0
  216.  
  217.         parser = UrlParser()
  218.  
  219.         params = parser.getParams()
  220.  
  221.         mode = parser.getIntParam(params, "mode")
  222.  
  223.         channelsArray = self.JsonToSortedTab(self.getJsonFromAPI(url))
  224.  
  225.         if len(channelsArray) > 0:
  226.  
  227.             try:
  228.  
  229.                 if channelsArray[0][1] == 'Null':
  230.  
  231.                     msg = Messages()
  232.  
  233.                     msg.Warning(t(57001).encode('utf-8'), t(57004).encode('utf-8'))
  234.  
  235.                 elif channelsArray[0][1] != 'Error' and channelsArray[0][1] != 'Null':
  236.  
  237.                     for i in range(len(channelsArray)):
  238.  
  239.                         k = channelsArray[i][1]
  240.  
  241.                         cid = k['cid']
  242.  
  243.                         name = self.decode(k['channel_name']).replace("\"", "")
  244.  
  245.                         title = self.decode(k['channel_title']).replace("\"", "")
  246.  
  247.                         desc = self.decode(k['channel_description']).replace("\"", "")
  248.  
  249.                         tags = self.decode(k['channel_tags']).replace("\"", "")
  250.  
  251.                         img = k['channel_image']
  252.  
  253.                         online = k['channel_online']
  254.  
  255.                         rank = k['rank']
  256.  
  257.                         bitrate = k['multibitrate']
  258.  
  259.                         user = self.decode(k['user_name']).replace("\"", "")
  260.  
  261.                         image = iconUrl + "no_video.png"
  262.  
  263.                         if img == '1':
  264.  
  265.                             image = iconUrl + cid + ".jpg"
  266.  
  267.                         if online == '2':
  268.  
  269.                             action = 1
  270.  
  271.                         else:
  272.  
  273.                             action = 0
  274.  
  275.                         self.addChannelToXBMC(str(mode), str(action), cid, title, image, desc, tags, user, name)
  276.  
  277.                     s = Settings()
  278.  
  279.                     s.setViewMode('other')
  280.  
  281.                     xbmcplugin.endOfDirectory(int(sys.argv[1]))
  282.  
  283.                     if mode == 1:
  284.  
  285.                         xbmcplugin.addSortMethod(handle = int(sys.argv[1]), sortMethod = xbmcplugin.SORT_METHOD_VIDEO_TITLE)
  286.  
  287.             except KeyError, keyerr:
  288.  
  289.                 msg = Messages()
  290.  
  291.                 print keyerr
  292.  
  293.                 msg.Error(t(57001).encode('utf-8'), t(57025).encode('utf-8'))                
  294.  
  295.         else:
  296.  
  297.             msg = Messages()
  298.  
  299.             msg.Error(t(57001).encode('utf-8'), t(57004).encode('utf-8'))
  300.  
  301.  
  302.  
  303.     def addChannelToXBMC(self, mode, action, cid, title, img, desc, tags, user, name):
  304.  
  305.         status = t(57033).encode('utf-8')
  306.  
  307.         label = title
  308.  
  309.         if desc == None or desc == '' or desc == 'null':
  310.  
  311.             desc = t(57016).encode('utf-8')
  312.  
  313.         if tags == None or tags == 'null':
  314.  
  315.             tags = t(57017).encode('utf-8')
  316.  
  317.         if title == '':
  318.  
  319.             title = name
  320.  
  321.         if int(action) == 0:
  322.  
  323.             if display == 'color':
  324.  
  325.                 status = '[COLOR red]' + t(57030).encode('utf-8') + '[/COLOR]'
  326.  
  327.             elif display == 'gray':
  328.  
  329.                 status = t(57030).encode('utf-8')
  330.  
  331.         elif int(action) == 1:
  332.  
  333.             if display == 'color':
  334.  
  335.                 status = '[COLOR green]' + t(57029).encode('utf-8') + '[/COLOR]'
  336.  
  337.             elif display == 'gray':
  338.  
  339.                 status = t(57029).encode('utf-8')
  340.  
  341.         if display == 'color':
  342.  
  343.             label = ' [B]%s[/B]  %s [I]%s[/I] %s [I]%s[/I]    [B]%s[/B] ' % (title, t(57031).encode('utf-8'), name, t(57032).encode('utf-8'), user, status)
  344.  
  345.         elif display == 'gray':
  346.  
  347.             label = ' %s %s %s %s %s    %s ' % (title, t(57031).encode('utf-8'), name, t(57032).encode('utf-8'), user, status)
  348.  
  349.         liz = xbmcgui.ListItem(label, iconImage = "DefaultFolder.png", thumbnailImage = img)
  350.  
  351.         liz.setProperty("IsPlayable", "false")
  352.  
  353.         liz.setInfo(type = "Video", infoLabels={ "Title": title,
  354.  
  355.                                            "Plot": desc,
  356.  
  357.                                            "Studio": "WEEB.TV",
  358.  
  359.                                            "Tagline": tags,
  360.  
  361.                                            "Status": status,
  362.  
  363.                                            "Aired": user } )
  364.  
  365.         u = '%s?mode=%d&action=%d&cid=%d&title=%s' % (sys.argv[0], int(mode), int(action), int(cid), urllib.quote_plus(title))
  366.  
  367.         xbmcplugin.addDirectoryItem(handle = int(sys.argv[1]), url = u, listitem = liz, isFolder = False)
  368.  
  369.  
  370.  
  371. class UrlParser:
  372.  
  373.     def __init__(self):
  374.  
  375.         pass
  376.  
  377.  
  378.  
  379.     def getParam(self, params, name):
  380.  
  381.         try:
  382.  
  383.             result = params[name]
  384.  
  385.             result = urllib.unquote_plus(result)
  386.  
  387.             return result
  388.  
  389.         except:
  390.  
  391.             return None
  392.  
  393.  
  394.  
  395.     def getIntParam (self, params, name):
  396.  
  397.         try:
  398.  
  399.             param = self.getParam(params, name)
  400.  
  401.             return int(param)
  402.  
  403.         except:
  404.  
  405.             return None
  406.  
  407.  
  408.  
  409.     def getBoolParam (self, params, name):
  410.  
  411.         try:
  412.  
  413.             param = self.getParam(params,name)
  414.  
  415.             return 'True' == param
  416.  
  417.         except:
  418.  
  419.             return None
  420.  
  421.  
  422.  
  423.     def getParams(self, paramstring = sys.argv[2]):
  424.  
  425.         param=[]
  426.  
  427.         if len(paramstring) >= 2:
  428.  
  429.             params = paramstring
  430.  
  431.             cleanedparams = params.replace('?', '')
  432.  
  433.             if (params[len(params)-1] == '/'):
  434.  
  435.                 params = params[0:len(params)-2]
  436.  
  437.             pairsofparams = cleanedparams.split('&')
  438.  
  439.             param = {}
  440.  
  441.             for i in range(len(pairsofparams)):
  442.  
  443.                 splitparams = {}
  444.  
  445.                 splitparams = pairsofparams[i].split('=')
  446.  
  447.                 if (len(splitparams)) == 2:
  448.  
  449.                     param[splitparams[0]] = splitparams[1]
  450.  
  451.         return param
  452.  
  453.  
  454.  
  455. class RTMP:    
  456.  
  457.     def __init__(self):
  458.  
  459.         pass
  460.  
  461.  
  462.  
  463.     def ConnectionParams(self, channel):
  464.  
  465.         data = None
  466.  
  467.         if login == '' and password == '':
  468.  
  469.             values = { 'cid': channel, 'platform': 'XBMC' }
  470.  
  471.         else:
  472.  
  473.             values = { 'cid': channel, 'platform': 'XBMC', 'username': login, 'userpassword': password }
  474.  
  475.         try:
  476.  
  477.             parser = UrlParser()
  478.  
  479.             headers = { 'User-Agent' : HOST }
  480.  
  481.             data = urllib.urlencode(values)
  482.  
  483.             reqUrl = urllib2.Request(playerUrl, data, headers)
  484.  
  485.             response = urllib2.urlopen(reqUrl)
  486.  
  487.             resLink = response.read()
  488.  
  489.             params = parser.getParams(resLink)
  490.  
  491.  
  492.  
  493.             status = parser.getParam(params, "0")
  494.  
  495.             premium = parser.getIntParam(params, "5")
  496.  
  497.             rtmpLink = parser.getParam(params, "10")
  498.  
  499.             playPath = parser.getParam(params, "11")
  500.  
  501.             ticket = parser.getParam(params, "73")
  502.  
  503.  
  504.  
  505.             data = { 'rtmp': rtmpLink, 'ticket': ticket, 'playpath': playPath, 'premium': premium, 'status': status }
  506.  
  507.         except urllib2.URLError, urlerr:
  508.  
  509.             msg = Messages()
  510.  
  511.             data = { 'rtmp': None, 'ticket': None, 'playpath': None, 'premium': premium, 'status': status }
  512.  
  513.             print urlerr
  514.  
  515.             msg.Error(t(57014).encode('utf-8'), t(57015).encode('utf-8'), t(57003).encode('utf-8'))
  516.  
  517.         return data
  518.  
  519.  
  520.  
  521.     def GetLinkParameters(self, channel, bitrate):
  522.  
  523.         dataLink = {}
  524.  
  525.         valTabA = self.ConnectionParams(channel)
  526.  
  527.         rtmpLink = valTabA['rtmp']
  528.  
  529.         ticket = valTabA['ticket']
  530.  
  531.         playpath = valTabA['playpath']
  532.  
  533.         premium = valTabA['premium']
  534.  
  535.         status = valTabA['status']
  536.  
  537.         if bitrate == '1' and multi == 'true':
  538.  
  539.             playpath = playpath + 'HI'
  540.  
  541.         rtmp = str(rtmpLink) + '/' + str(playpath)
  542.  
  543.         rtmp += ' swfUrl='  + str(ticket)
  544.  
  545.         rtmp += ' pageUrl=token'
  546.  
  547.         rtmp += ' live=true'
  548.  
  549.         print 'Output rtmp link: %s' % (rtmp)
  550.  
  551.         return { 'rtmp': rtmp, 'premium': premium, 'status': status }
  552.  
  553.  
  554.  
  555. class VideoPlayer(xbmc.Player):
  556.  
  557.     def __init__(self, *args, **kwargs):
  558.  
  559.         self.is_active = True
  560.  
  561.         print "#Starting control VideoPlayer events#"
  562.  
  563.  
  564.  
  565.     def setPremium(self, premium):
  566.  
  567.         self.premium = premium
  568.  
  569.  
  570.  
  571.     def getPremium(self):
  572.  
  573.         return self.premium
  574.  
  575.  
  576.  
  577.     def onPlayBackPaused(self):
  578.  
  579.         print "#Im paused#"
  580.  
  581.         ThreadPlayerControl("Stop").start()
  582.  
  583.         self.is_active = False
  584.  
  585.  
  586.  
  587.     def onPlayBackResumed(self):
  588.  
  589.         print "#Im Resumed #"
  590.  
  591.  
  592.  
  593.     def onPlayBackStarted(self):
  594.  
  595.         print "#Playback Started#"
  596.  
  597.         try:
  598.  
  599.             print "#Im playing :: " + self.getPlayingFile()
  600.  
  601.         except:
  602.  
  603.             print "#I failed get what Im playing#"
  604.  
  605.  
  606.  
  607.     def onPlayBackEnded(self):
  608.  
  609.         msg = Messages()
  610.  
  611.         print "#Playback Ended#"
  612.  
  613.         self.is_active = False
  614.  
  615.         if self.getPremium() == 0:
  616.  
  617.             msg.Warning(t(57018).encode('utf-8'), t(57019).encode('utf-8'), t(57020).encode('utf-8'))
  618.  
  619.         else:
  620.  
  621.             msg.Warning(t(57018).encode('utf-8'), t(57027).encode('utf-8'))
  622.  
  623.  
  624.  
  625.     def onPlayBackStopped(self):
  626.  
  627.         print "## Playback Stopped ##"
  628.  
  629.         self.is_active = False
  630.  
  631.  
  632.  
  633.     def sleep(self, s):
  634.  
  635.         xbmc.sleep(s)
  636.  
  637.  
  638.  
  639. class InitPlayer:
  640.  
  641.     def __init__(self):
  642.  
  643.         pass
  644.  
  645.  
  646.  
  647.     def getChannelInfoFromJSON(self, channel):
  648.  
  649.         chan = ShowList()
  650.  
  651.         dataInfo = { 'title': '', 'image': '', 'bitrate': '' }
  652.  
  653.         try:
  654.  
  655.             channelsArray = chan.getJsonFromAPI(apiUrl)
  656.  
  657.             for v,k in channelsArray.items():
  658.  
  659.                 if channel == int(k['cid']):
  660.  
  661.                     cid = k['cid']
  662.  
  663.                     title = chan.decode(k['channel_title']).replace("\"", "")
  664.  
  665.                     bitrate = k['multibitrate']
  666.  
  667.                     img = k['channel_image']
  668.  
  669.                     image = iconUrl + "no_video.png"
  670.  
  671.                     if img == '1':
  672.  
  673.                         image = iconUrl + cid + ".jpg"
  674.  
  675.                     dataInfo = { 'title': title, 'image': image, 'bitrate': bitrate }
  676.  
  677.                     break
  678.  
  679.         except TypeError, typerr:
  680.  
  681.             print typerr
  682.  
  683.         return dataInfo
  684.  
  685.  
  686.  
  687.     def LoadVideoLink(self, channel):
  688.  
  689.         res = True
  690.  
  691.         rtmp = RTMP()
  692.  
  693.         val = self.getChannelInfoFromJSON(channel)
  694.  
  695.         videoLink =  rtmp.GetLinkParameters(channel, val['bitrate'])            
  696.  
  697.         if videoLink['status'] == '1':
  698.  
  699.             if videoLink['rtmp'].startswith('rtmp'):
  700.  
  701.                 liz = xbmcgui.ListItem(val['title'], iconImage = val['image'], thumbnailImage = val['image'])
  702.  
  703.                 liz.setInfo( type="Video", infoLabels={ "Title": val['title'], } )
  704.  
  705.                 try:
  706.  
  707.                     player = VideoPlayer()
  708.  
  709.                     player.setPremium(int(videoLink['premium']))
  710.  
  711.                     if videoLink['premium'] == 0:
  712.  
  713.                         msg = Messages()
  714.  
  715.                         msg.Warning(t(57034).encode('utf-8'), t(57036).encode('utf-8'), t(57037).encode('utf-8'), t(57038).encode('utf-8'))                
  716.  
  717.                     player.play(videoLink['rtmp'], liz)
  718.  
  719.                     while player.is_active:
  720.  
  721.                         player.sleep(100)
  722.  
  723.                 except:
  724.  
  725.                     msg = Messages()
  726.  
  727.                     msg.Error(t(57018).encode('utf-8'), t(57021).encode('utf-8'), t(57028).encode('utf-8'))
  728.  
  729.             else:
  730.  
  731.                 msg = Messages()
  732.  
  733.                 msg.Error(t(57018).encode('utf-8'), t(57022).encode('utf-8'))
  734.  
  735.         elif videoLink['status'] == '-1':
  736.  
  737.             msg = Messages()
  738.  
  739.             msg.Warning(t(57018).encode('utf-8'), t(57043).encode('utf-8'))
  740.  
  741.         elif videoLink['status'] == '-2':
  742.  
  743.             msg = Messages()
  744.  
  745.             msg.Warning(t(57018).encode('utf-8'), t(57044).encode('utf-8'))
  746.  
  747.         elif videoLink['status'] == '-3':
  748.  
  749.             msg = Messages()
  750.  
  751.             msg.Warning(t(57018).encode('utf-8'), t(57045).encode('utf-8'))
  752.  
  753.         elif videoLink['status'] == '-4':
  754.  
  755.             msg = Messages()
  756.  
  757.             msg.Warning(t(57018).encode('utf-8'), t(57046).encode('utf-8'), t(57047).encode('utf-8'))  
  758.  
  759.         else:
  760.  
  761.             msg = Messages()
  762.  
  763.             msg.Warning(t(57018).encode('utf-8'), t(57042).encode('utf-8'))
  764.  
  765.         return res
  766.  
  767.  
  768.  
  769. class ThreadPlayerControl(threading.Thread):
  770.  
  771.     def __init__(self, command):
  772.  
  773.         self.command = command
  774.  
  775.         threading.Thread.__init__ (self)
  776.  
  777.  
  778.  
  779.     def run(self):
  780.  
  781.         xbmc.executebuiltin('PlayerControl(' + self.command + ')')
  782.  
  783.  
  784.  
  785. class Messages:
  786.  
  787.     def __init__(self):
  788.  
  789.         pass
  790.  
  791.  
  792.  
  793.     def Error(self, title, text1, text2 = "", text3 = ""):
  794.  
  795.         err = gui.Windows()
  796.  
  797.         err.Error(title, text1, text2, text3)
  798.  
  799.  
  800.  
  801.     def Warning(self, title, text1, text2 = "", text3 = ""):
  802.  
  803.         warn = gui.Windows()
  804.  
  805.         warn.Warning(title, text1, text2, text3)
  806.  
  807.  
  808.  
  809. class Handler:
  810.  
  811.     def __init__(self):
  812.  
  813.         pass
  814.  
  815.  
  816.  
  817.     def run(self, mode):
  818.  
  819.         s = Settings()
  820.  
  821.         parser = UrlParser()
  822.  
  823.         params = parser.getParams()
  824.  
  825.         url = ""
  826.  
  827.         mode = parser.getIntParam(params, "mode")
  828.  
  829.         cid = parser.getIntParam(params, "cid")
  830.  
  831.         title = parser.getParam(params, "title")
  832.  
  833.         action = parser.getIntParam(params, "action")
  834.  
  835.         if mode > 0 and action == None:
  836.  
  837.             if mode > 0:
  838.  
  839.                 showlist = ShowList()
  840.  
  841.                 if mode == 1:
  842.  
  843.                     url = apiUrl + "&option=online-alphabetical"
  844.  
  845.                 elif mode == 2:
  846.  
  847.                     url = apiUrl + "&option=online-now-viewed"
  848.  
  849.                 elif mode == 3:
  850.  
  851.                     url = apiUrl + "&option=online-most-viewed"
  852.  
  853.                 elif mode == 4:
  854.  
  855.                     url = apiUrl + "&option=offline-ranking"
  856.  
  857.                 elif mode == 5:
  858.  
  859.                     url = apiUrl + "&option=all-ranking"
  860.  
  861.                 showlist.loadChannels(url)
  862.  
  863.         elif mode > 0 and action == 1:
  864.  
  865.             s.setViewMode('other')
  866.  
  867.             if cid > 0 and title != "":
  868.  
  869.                 run = InitPlayer()
  870.  
  871.                 run.LoadVideoLink(cid)
  872.  
  873.         elif mode > 0 and action == 0:
  874.  
  875.             s.setViewMode('other')
  876.  
  877.             msg = Messages()
  878.  
  879.             msg.Warning(t(57005).encode('utf-8'), t(57006).encode('utf-8'), t(57007).encode('utf-8'), t(57008).encode('utf-8'))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement