No Description

epg2xml.py 33KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. #!/usr/bin/env python3.7
  2. # -*- coding: utf-8 -*-
  3. from __future__ import print_function
  4. import importlib.util
  5. import os
  6. import sys
  7. import json
  8. import locale
  9. import datetime
  10. import codecs
  11. import socket
  12. import re
  13. from xml.sax.saxutils import escape, unescape
  14. import argparse
  15. import pprint
  16. from functools import partial
  17. import time
  18. try:
  19. importlib.util.find_spec('bs4')
  20. from bs4 import BeautifulSoup, SoupStrainer
  21. except ImportError:
  22. print("Error : ", "BeautifulSoup 모듈이 설치되지 않았습니다.", file=sys.stderr)
  23. sys.exit()
  24. try:
  25. importlib.util.find_spec('lxml')
  26. from lxml import html
  27. except ImportError:
  28. print("Error : ", "lxml 모듈이 설치되지 않았습니다.", file=sys.stderr)
  29. sys.exit()
  30. try:
  31. importlib.util.find_spec('requests')
  32. import requests
  33. except ImportError:
  34. print("Error : ", "requests 모듈이 설치되지 않았습니다.", file=sys.stderr)
  35. sys.exit()
  36. sys.stdout.reconfigure(encoding='utf-8')
  37. sys.stdin.reconfigure(encoding='utf-8')
  38. # if not sys.version_info[:2] == (2, 7):
  39. # print("Error : ", "python 2.7 버전이 필요합니다.", file=sys.stderr)
  40. # sys.exit()
  41. # Set variable
  42. __version__ = '2.0.0'
  43. debug = False
  44. today = datetime.date.today()
  45. ua = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116'}
  46. timeout = 5
  47. htmlparser = 'lxml'
  48. CHANNEL_ERROR = ' 존재하지 않는 채널입니다.'
  49. CONTENT_ERROR = ' EPG 정보가 없습니다.'
  50. HTTP_ERROR = ' EPG 정보를 가져오는데 문제가 있습니다.'
  51. SOCKET_ERROR = 'xmltv.sock 파일을 찾을 수 없습니다.'
  52. JSON_FILE_ERROR = 'json 파일을 읽을 수 없습니다.'
  53. JSON_SYNTAX_ERROR = 'json 파일 형식이 잘못되었습니다.'
  54. # Get epg data
  55. def getEpg():
  56. Channelfile = os.path.dirname(os.path.abspath(__file__)) + '/Channel.json'
  57. ChannelInfos = []
  58. try:
  59. with open(Channelfile, encoding="utf-8") as f: # Read Channel Information file
  60. Channeldatajson = json.load(f)
  61. except EnvironmentError:
  62. printError("Channel." + JSON_FILE_ERROR)
  63. sys.exit()
  64. except ValueError:
  65. printError("Channel." + JSON_SYNTAX_ERROR)
  66. sys.exit()
  67. print('<?xml version="1.0" encoding="UTF-8"?>')
  68. print('<!DOCTYPE tv SYSTEM "xmltv.dtd">\n')
  69. print('<tv generator-info-name="epg2xml ' + __version__ + '">')
  70. # My Channel 정의
  71. for Channeldata in Channeldatajson: #Get Channel & Print Channel info
  72. # if Channeldata['Id'] is 223:
  73. ChannelId = Channeldata['Id']
  74. ChannelName = escape(Channeldata['Name'])
  75. ChannelSource = Channeldata['Source']
  76. ChannelServiceId = Channeldata['ServiceId']
  77. ChannelIconUrl = escape(Channeldata['Icon_url'])
  78. if MyISP != "ALL" and Channeldata[MyISP+'Ch'] is not None:
  79. ChannelInfos.append([ChannelId, ChannelName, ChannelSource, ChannelServiceId])
  80. ChannelNumber = str(Channeldata[MyISP+'Ch']);
  81. ChannelISPName = escape(Channeldata[MyISP+' Name'])
  82. print(' <channel id="%s">' % (ChannelId))
  83. print(' <display-name>%s</display-name>' % (ChannelName))
  84. print(' <display-name>%s</display-name>' % (ChannelISPName))
  85. print(' <display-name>%s</display-name>' % (ChannelNumber))
  86. print(' <display-name>%s</display-name>' % (ChannelNumber+' '+ChannelISPName))
  87. if IconUrl:
  88. print(' <icon src="%s/%s.png" />' % (IconUrl, ChannelId))
  89. else :
  90. print(' <icon src="%s" />' % (ChannelIconUrl))
  91. print(' </channel>')
  92. elif MyISP == "ALL":
  93. ChannelInfos.append([ChannelId, ChannelName, ChannelSource, ChannelServiceId])
  94. print(' <channel id="%s">' % (ChannelId))
  95. print(' <display-name>%s</display-name>' % (ChannelName))
  96. if IconUrl:
  97. print(' <icon src="%s/%s.png" />' % (IconUrl, ChannelId))
  98. else :
  99. print(' <icon src="%s" />' % (ChannelIconUrl))
  100. print(' </channel>')
  101. # Print Program Information
  102. for ChannelInfo in ChannelInfos:
  103. ChannelId = ChannelInfo[0]
  104. ChannelName = ChannelInfo[1]
  105. ChannelSource = ChannelInfo[2]
  106. ChannelServiceId = ChannelInfo[3]
  107. if(debug) : printLog(ChannelName + ' 채널 EPG 데이터를 가져오고 있습니다')
  108. if ChannelSource == 'KT':
  109. GetEPGFromKT(ChannelInfo)
  110. elif ChannelSource == 'LG':
  111. GetEPGFromLG(ChannelInfo)
  112. elif ChannelSource == 'SK':
  113. GetEPGFromSK(ChannelInfo)
  114. elif ChannelSource == 'SKB':
  115. GetEPGFromSKB(ChannelInfo)
  116. elif ChannelSource == 'NAVER':
  117. GetEPGFromNaver(ChannelInfo)
  118. print('</tv>')
  119. # Get EPG data from KT
  120. def GetEPGFromKT(ChannelInfo):
  121. ChannelId = ChannelInfo[0]
  122. ChannelName = ChannelInfo[1]
  123. ServiceId = ChannelInfo[3]
  124. epginfo = []
  125. url = 'http://tv.kt.com/tv/channel/pSchedule.asp'
  126. for k in range(period):
  127. day = today + datetime.timedelta(days=k)
  128. params = {'ch_type':'1', 'view_type':'1', 'service_ch_no':ServiceId, 'seldate':day.strftime('%Y%m%d')}
  129. try:
  130. response = requests.post(url, data=params, headers=ua, timeout=timeout)
  131. response.raise_for_status()
  132. html_data = (response.content).decode("euc-kr")
  133. # data = unicode(html_data, 'euc-kr', 'ignore').encode('utf-8', 'ignore')
  134. data = html_data
  135. print(data)
  136. strainer = SoupStrainer('tbody')
  137. soup = BeautifulSoup(data, htmlparser, parse_only=strainer)
  138. html = soup.find_all('tr') if soup.find('tbody') else ''
  139. if(html):
  140. for row in html:
  141. for cell in [row.find_all('td')]:
  142. startTime = endTime = programName = subprogramName = desc = actors = producers = category = episode = ''
  143. rebroadcast = False
  144. for minute, program, category in zip(cell[1].find_all('p'), cell[2].find_all('p'), cell[3].find_all('p')):
  145. startTime = str(day) + ' ' + cell[0].text.strip() + ':' + minute.text.strip()
  146. startTime = datetime.datetime.strptime(startTime, '%Y-%m-%d %H:%M')
  147. startTime = startTime.strftime('%Y%m%d%H%M%S')
  148. programName = program.text.replace('방송중 ', '').strip()
  149. category = category.text.strip()
  150. for image in [program.find_all('img', alt=True)]:
  151. rating = 0
  152. grade = re.match('([\d,]+)',image[0]['alt'])
  153. if not (grade is None): rating = int(grade.group(1))
  154. else: rating = 0
  155. #ChannelId, startTime, programName, subprogramName, desc, actors, producers, category, episode, rebroadcast, rating
  156. epginfo.append([ChannelId, startTime, programName, subprogramName, desc, actors, producers, category, episode, rebroadcast, rating])
  157. time.sleep(0.001)
  158. else:
  159. if(debug): printError(ChannelName + CONTENT_ERROR)
  160. else: pass
  161. except (requests.exceptions.RequestException) as e:
  162. if(debug): printError(ChannelName + str(e))
  163. else: pass
  164. if(epginfo) :
  165. epgzip(epginfo)
  166. # Get EPG data from LG
  167. def GetEPGFromLG(ChannelInfo):
  168. ChannelId = ChannelInfo[0]
  169. ChannelName = ChannelInfo[1]
  170. ServiceId = ChannelInfo[3]
  171. epginfo = []
  172. url = 'http://www.uplus.co.kr/css/chgi/chgi/RetrieveTvSchedule.hpi'
  173. for k in range(period):
  174. day = today + datetime.timedelta(days=k)
  175. params = {'chnlCd': ServiceId, 'evntCmpYmd': day.strftime('%Y%m%d')}
  176. try:
  177. response = requests.post(url, data=params, headers=ua, timeout=timeout)
  178. response.raise_for_status()
  179. html_data = (response.content).decode("euc-kr")
  180. # data = unicode(html_data, 'euc-kr', 'ignore').encode('utf-8', 'ignore')
  181. data = html_data
  182. data = data.replace('<재>', '&lt;재&gt;').replace(' [..','').replace(' (..', '')
  183. strainer = SoupStrainer('table')
  184. soup = BeautifulSoup(data, htmlparser, parse_only=strainer)
  185. html = soup.find('table').tbody.find_all('tr') if soup.find('table') else ''
  186. if(html):
  187. for row in html:
  188. for cell in [row.find_all('td')]:
  189. startTime = endTime = programName = subprogramName = desc = actors = producers = category = episode = ''
  190. rebroadcast = False
  191. rating = 0
  192. startTime = str(day) + ' ' + cell[0].text
  193. startTime = datetime.datetime.strptime(startTime, '%Y-%m-%d %H:%M')
  194. startTime = startTime.strftime('%Y%m%d%H%M%S')
  195. rating = 0 if cell[1].find('span', {'class': 'tag cte_all'}).text.strip()=="All" else int(cell[1].find('span', {'class': 'tag cte_all'}).text.strip())
  196. cell[1].find('span', {'class': 'tagGroup'}).decompose()
  197. pattern = '(<재>)?\s?(?:\[.*?\])?(.*?)(?:\[(.*)\])?\s?(?:\(([\d,]+)회\))?$'
  198. matches = re.match(pattern, cell[1].text.strip())
  199. if not (matches is None):
  200. programName = matches.group(2).strip() if matches.group(2) else ''
  201. subprogramName = matches.group(3).strip() if matches.group(3) else ''
  202. episode = matches.group(4) if matches.group(4) else ''
  203. rebroadcast = True if matches.group(1) else False
  204. category = cell[2].text.strip()
  205. #ChannelId, startTime, programName, subprogramName, desc, actors, producers, category, episode, rebroadcast, rating
  206. epginfo.append([ChannelId, startTime, programName, subprogramName, desc, actors, producers, category, episode, rebroadcast, rating])
  207. time.sleep(0.001)
  208. else:
  209. if(debug): printError(ChannelName + CONTENT_ERROR)
  210. else: pass
  211. except (requests.exceptions.RequestException) as e:
  212. if(debug): printError(ChannelName + str(e))
  213. else: pass
  214. if(epginfo) :
  215. epgzip(epginfo)
  216. # Get EPG data from SK
  217. def GetEPGFromSK(ChannelInfo):
  218. ChannelId = ChannelInfo[0]
  219. ChannelName = ChannelInfo[1]
  220. ServiceId = ChannelInfo[3]
  221. lastday = today + datetime.timedelta(days=period-1)
  222. url = 'http://m.btvplus.co.kr/common/inc/IFGetData.do'
  223. params = {'variable': 'IF_LIVECHART_DETAIL', 'pcode':'|^|start_time=' + today.strftime('%Y%m%d') + '00|^|end_time='+ lastday.strftime('%Y%m%d') + '24|^|svc_id=' + str(ServiceId)}
  224. try:
  225. response = requests.post(url, data=params, headers=ua, timeout=timeout)
  226. response.raise_for_status()
  227. json_data = response.text
  228. try:
  229. data = json.loads(json_data, encoding='utf-8')
  230. if (data['channel'] is None) :
  231. if(True): printError(ChannelName + CONTENT_ERROR)
  232. else: pass
  233. else :
  234. programs = data['channel']['programs']
  235. for program in programs:
  236. startTime = endTime = programName = subprogramName = desc = actors = producers = category = episode = ''
  237. rebroadcast = False
  238. rating = 0
  239. programName = program['programName'].replace('...', '>').encode('utf-8')
  240. pattern = '^(.*?)(?:\s*[\(<]([\d,회]+)[\)>])?(?:\s*<([^<]*?)>)?(\((재)\))?$'
  241. matches = re.match(pattern, programName.decode('utf-8'))
  242. if not (matches is None):
  243. programName = matches.group(1).strip() if matches.group(1) else ''
  244. subprogramName = matches.group(3).strip() if matches.group(3) else ''
  245. episode = matches.group(2).replace('회', '') if matches.group(2) else ''
  246. episode = '' if episode== '0' else episode
  247. rebroadcast = True if matches.group(5) else False
  248. startTime = datetime.datetime.fromtimestamp(int(program['startTime'])/1000)
  249. startTime = startTime.strftime('%Y%m%d%H%M%S')
  250. endTime = datetime.datetime.fromtimestamp(int(program['endTime'])/1000)
  251. endTime = endTime.strftime('%Y%m%d%H%M%S')
  252. desc = program['synopsis'] if program['synopsis'] else ''
  253. actors = program['actorName'].replace('...','').strip(', ') if program['actorName'] else ''
  254. producers = program['directorName'].replace('...','').strip(', ') if program['directorName'] else ''
  255. if not (program['mainGenreName'] is None) :
  256. category = program['mainGenreName']
  257. rating = int(program['ratingCd']) if program['ratingCd'] else 0
  258. programdata = {'channelId':ChannelId, 'startTime':startTime, 'endTime':endTime, 'programName':programName, 'subprogramName':subprogramName, 'desc':desc, 'actors':actors, 'producers':producers, 'category':category, 'episode':episode, 'rebroadcast':rebroadcast, 'rating':rating}
  259. writeProgram(programdata)
  260. time.sleep(0.001)
  261. except ValueError:
  262. if(debug): printError(ChannelName + CONTENT_ERROR)
  263. else: pass
  264. except (requests.exceptions.RequestException) as e:
  265. if(debug): printError(ChannelName + str(e))
  266. else: pass
  267. #Get EPG data from SKB
  268. def GetEPGFromSKB(ChannelInfo):
  269. ChannelId = ChannelInfo[0]
  270. ChannelName = ChannelInfo[1]
  271. ServiceId = ChannelInfo[3]
  272. url = 'http://m.skbroadband.com/content/realtime/Channel_List.do'
  273. epginfo = []
  274. for k in range(period):
  275. day = today + datetime.timedelta(days=k)
  276. params = {'key_depth2': ServiceId, 'key_depth3': day.strftime('%Y%m%d')}
  277. try:
  278. response = requests.get(url, params=params, headers=ua, timeout=timeout)
  279. response.raise_for_status()
  280. html_data = (response.content).decode("euc-kr")
  281. # data = unicode(html_data, 'euc-kr', 'ignore').encode('utf-8', 'ignore')
  282. data = html_data
  283. data = re.sub("EUC-KR", 'utf-8', data)
  284. data = re.sub('<!--(.*?)-->', '', data, 0, re.I|re.S)
  285. data = re.sub('<span class="round_flag flag02">(.*?)</span>', '', data)
  286. data = re.sub('<span class="round_flag flag03">(.*?)</span>', '', data)
  287. data = re.sub('<span class="round_flag flag04">(.*?)</span>', '', data)
  288. data = re.sub('<span class="round_flag flag09">(.*?)</span>', '', data)
  289. data = re.sub('<span class="round_flag flag10">(.*?)</span>', '', data)
  290. data = re.sub('<span class="round_flag flag11">(.*?)</span>', '', data)
  291. data = re.sub('<span class="round_flag flag12">(.*?)</span>', '', data)
  292. data = re.sub('<strong class="hide">프로그램 안내</strong>', '', data)
  293. data = re.sub('<p class="cont">(.*)', partial(replacement, tag='p') , data)
  294. data = re.sub('<p class="tit">(.*)', partial(replacement, tag='p') , data)
  295. strainer = SoupStrainer('div', {'id':'uiScheduleTabContent'})
  296. soup = BeautifulSoup(data, htmlparser, parse_only=strainer)
  297. html = soup.find_all('li',{'class':'list'}) if soup.find_all('li') else ''
  298. if(html):
  299. for row in html:
  300. startTime = endTime = programName = subprogramName = desc = actors = producers = category = episode = ''
  301. rebroadcast = False
  302. rating = 0
  303. startTime = str(day) + ' ' + row.find('p', {'class':'time'}).text
  304. startTime = datetime.datetime.strptime(startTime, '%Y-%m-%d %H:%M')
  305. startTime = startTime.strftime('%Y%m%d%H%M%S')
  306. cell = row.find('p', {'class':'cont'})
  307. grade = row.find('i', {'class':'hide'})
  308. if not(grade is None):
  309. # rating = int(grade.text.decode('string_escape').replace('세 이상','').strip())
  310. rating = int(grade.text.replace('세 이상','').strip())
  311. if(cell):
  312. if cell.find('span'):
  313. cell.span.decompose()
  314. # cell = cell.text.decode('string_escape').strip()
  315. #cell = cell.text.decode('string_escape').strip()
  316. #print (chardet.detect(cell.text.strip()))
  317. cell=cell.text.strip()
  318. # print (chardet.detect(bytes(cell,'utf-8')))
  319. # cell = cell.text.strip()
  320. pattern = "^(.*?)(\(([\d,]+)회\))?(<(.*)>)?(\((재)\))?$"
  321. # print (chardet.detect(pattern))
  322. matches = re.match(pattern, cell)
  323. if not(matches is None) :
  324. programName = matches.group(1) if matches.group(1) else ''
  325. subprogramName = matches.group(5) if matches.group(5) else ''
  326. rebroadcast = True if matches.group(7) else False
  327. episode = matches.group(3) if matches.group(3) else ''
  328. #ChannelId, startTime, programName, subprogramName, desc, actors, producers, category, episode, rebroadcast, rating
  329. epginfo.append([ChannelId, startTime, programName, subprogramName, desc, actors, producers, category, episode, rebroadcast, rating])
  330. time.sleep(0.001)
  331. else:
  332. if(debug): printError(ChannelName + CONTENT_ERROR)
  333. else: pass
  334. except (requests.exceptions.RequestException) as e:
  335. if(debug): printError(ChannelName + str(e))
  336. else: pass
  337. if(epginfo) :
  338. epgzip(epginfo)
  339. # Get EPG data from Naver
  340. def GetEPGFromNaver(ChannelInfo):
  341. ChannelId = ChannelInfo[0]
  342. ChannelName = ChannelInfo[1]
  343. ServiceId = ChannelInfo[3]
  344. epginfo = []
  345. totaldate = []
  346. url = 'https://search.naver.com/p/csearch/content/batchrender_ssl.nhn'
  347. for k in range(period):
  348. day = today + datetime.timedelta(days=k)
  349. totaldate.append(day.strftime('%Y%m%d'))
  350. params = {'_callback': 'epg', 'fileKey': 'single_schedule_channel_day', 'pkid': '66', 'u1': 'single_schedule_channel_day', 'u2': ','.join(totaldate), 'u3': today.strftime('%Y%m%d'), 'u4': period, 'u5': ServiceId, 'u6': '1', 'u7': ChannelName + '편성표', 'u8': ChannelName + '편성표', 'where': 'nexearch'}
  351. try:
  352. response = requests.get(url, params=params, headers=ua, timeout=timeout)
  353. response.raise_for_status()
  354. json_data = re.sub(re.compile("/\*.*?\*/",re.DOTALL ) ,"" ,response.text.split("epg(")[1].strip(");").strip())
  355. try:
  356. data = json.loads(json_data, encoding='utf-8')
  357. for i, date in enumerate(data['displayDates']):
  358. for j in range(0,24):
  359. for program in data['schedules'][j][i]:
  360. startTime = endTime = programName = subprogramName = desc = actors = producers = category = episode = ''
  361. rebroadcast = False
  362. rating = 0
  363. programName = unescape(program['title'])
  364. startTime = date['date'] + ' ' + program['startTime']
  365. startTime = datetime.datetime.strptime(startTime, '%Y%m%d %H:%M')
  366. startTime = startTime.strftime('%Y%m%d%H%M%S')
  367. episode = program['episode'].replace('회','')
  368. rebroadcast = program['isRerun']
  369. rating = program['grade']
  370. #ChannelId, startTime, programName, subprogramName, desc, actors, producers, category, episode, rebroadcast, rating
  371. epginfo.append([ChannelId, startTime, programName, subprogramName, desc, actors, producers, category, episode, rebroadcast, rating])
  372. time.sleep(0.001)
  373. except ValueError:
  374. if(debug): printError(ChannelName + CONTENT_ERROR)
  375. else: pass
  376. except (requests.RequestException) as e:
  377. if(debug): printError(ChannelName + str(e))
  378. else: pass
  379. if(epginfo) :
  380. epgzip(epginfo)
  381. # Zip epginfo
  382. def epgzip(epginfo):
  383. epginfo = iter(epginfo)
  384. epg1 = next(epginfo)
  385. for epg2 in epginfo:
  386. programdata = {}
  387. ChannelId = epg1[0]
  388. startTime = epg1[1] if epg1[1] else ''
  389. endTime = epg2[1] if epg2[1] else ''
  390. programName = epg1[2] if epg1[2] else ''
  391. subprogramName = epg1[3] if epg1[3] else ''
  392. desc = epg1[4] if epg1[4] else ''
  393. actors = epg1[5] if epg1[5] else ''
  394. producers = epg1[6] if epg1[6] else ''
  395. category = epg1[7] if epg1[7] else ''
  396. episode = epg1[8] if epg1[8] else ''
  397. rebroadcast = True if epg1[9] else False
  398. rating = int(epg1[10]) if epg1[10] else 0
  399. programdata = {'channelId':ChannelId, 'startTime':startTime, 'endTime':endTime, 'programName':programName, 'subprogramName':subprogramName, 'desc':desc, 'actors':actors, 'producers':producers, 'category':category, 'episode':episode, 'rebroadcast':rebroadcast, 'rating':rating}
  400. writeProgram(programdata)
  401. epg1 = epg2
  402. # Write Program
  403. def writeProgram(programdata):
  404. ChannelId = programdata['channelId']
  405. startTime = programdata['startTime']
  406. endTime = programdata['endTime']
  407. programName = escape(programdata['programName']).strip()
  408. subprogramName = escape(programdata['subprogramName']).strip()
  409. matches = re.match('(.*) \(?(\d+부)\)?', unescape(programName))
  410. if not(matches is None):
  411. programName = escape(matches.group(1)).strip();
  412. subprogramName = escape(matches.group(2)) + ' ' + subprogramName
  413. subprogramName = subprogramName.strip()
  414. if programName is None:
  415. programName = subprogramName
  416. actors = escape(programdata['actors'])
  417. producers = escape(programdata['producers'])
  418. category = escape(programdata['category'])
  419. episode = programdata['episode']
  420. if episode:
  421. try:
  422. episode_ns = int(episode) - 1
  423. episode_ns = '0'+ '.' + str(episode_ns) + '.' + '0' + '/' + '0'
  424. except ValueError as ex:
  425. episode_ns = int(episode.split(',', 1)[0]) - 1
  426. episode_ns = '0'+ '.' + str(episode_ns) + '.' + '0' + '/' + '0'
  427. episode_on = episode
  428. rebroadcast = programdata['rebroadcast']
  429. if episode and addepisode == 'y': programName = programName + ' ('+ str(episode) + '회)'
  430. if rebroadcast == True and addrebroadcast == 'y' : programName = programName + ' (재)'
  431. if programdata['rating'] == 0 :
  432. rating = '전체 관람가'
  433. else :
  434. rating = '%s세 이상 관람가' % (programdata['rating'])
  435. if addverbose == 'y':
  436. desc = programName
  437. if subprogramName : desc = desc + '\n부제 : ' + subprogramName
  438. if rebroadcast == True and addrebroadcast == 'y' : desc = desc + '\n방송 : 재방송'
  439. if episode : desc = desc + '\n회차 : ' + str(episode) + '회'
  440. if category : desc = desc + '\n장르 : ' + category
  441. if actors : desc = desc + '\n출연 : ' + actors.strip()
  442. if producers : desc = desc + '\n제작 : ' + producers.strip()
  443. desc = desc + '\n등급 : ' + rating
  444. else:
  445. desc =''
  446. if programdata['desc'] : desc = desc + '\n' + escape(programdata['desc'])
  447. desc = re.sub(' +',' ', desc)
  448. contentTypeDict={'교양':'Arts / Culture (without music)', '만화':'Cartoons / Puppets', '교육':'Education / Science / Factual topics', '취미':'Leisure hobbies', '드라마':'Movie / Drama', '영화':'Movie / Drama', '음악':'Music / Ballet / Dance', '뉴스':'News / Current affairs', '다큐':'Documentary', '라이프':'Documentary', '시사/다큐':'Documentary', '연예':'Show / Game show', '스포츠':'Sports', '홈쇼핑':'Advertisement / Shopping'}
  449. contentType = ''
  450. for key, value in contentTypeDict.items():
  451. if key in category:
  452. contentType = value
  453. print(' <programme start="%s +0900" stop="%s +0900" channel="%s">' % (startTime, endTime, ChannelId))
  454. print(' <title lang="kr">%s</title>' % (programName))
  455. if subprogramName :
  456. print(' <sub-title lang="kr">%s</sub-title>' % (subprogramName))
  457. if addverbose=='y' :
  458. print(' <desc lang="kr">%s</desc>' % (desc))
  459. if actors or producers:
  460. print(' <credits>')
  461. if actors:
  462. for actor in actors.split(','):
  463. if actor.strip(): print(' <actor>%s</actor>' % (actor.strip()))
  464. if producers:
  465. for producer in producers.split(','):
  466. if producer.strip(): print(' <producer>%s</producer>' % (producer).strip())
  467. print(' </credits>')
  468. if category: print(' <category lang="kr">%s</category>' % (category))
  469. if contentType: print(' <category lang="en">%s</category>' % (contentType))
  470. if episode and addxmltvns == 'y' : print(' <episode-num system="xmltv_ns">%s</episode-num>' % (episode_ns))
  471. if episode and addxmltvns != 'y' : print(' <episode-num system="onscreen">%s</episode-num>' % (episode_on))
  472. if rebroadcast: print(' <previously-shown />')
  473. if rating:
  474. print(' <rating system="KMRB">')
  475. print(' <value>%s</value>' % (rating))
  476. print(' </rating>')
  477. print(' </programme>')
  478. def printLog(*args):
  479. print(*args, file=sys.stderr)
  480. def printError(*args):
  481. print("Error : ", *args, file=sys.stderr)
  482. def replacement(match, tag):
  483. if not(match is None):
  484. tag = tag.strip()
  485. programName = unescape(match.group(1)).replace('<','&lt;').replace('>','&gt;').strip()
  486. programName = '<'+ tag + ' class="cont">' + programName
  487. return programName
  488. else:
  489. return '';
  490. Settingfile = os.path.dirname(os.path.abspath(__file__)) + '/epg2xml.json'
  491. ChannelInfos = []
  492. try:
  493. with open(Settingfile, encoding="utf-8") as f: # Read Channel Information file
  494. Settings = json.load(f)
  495. MyISP = Settings['MyISP'] if 'MyISP' in Settings else 'ALL'
  496. default_output = Settings['output'] if 'output' in Settings else 'd'
  497. default_xml_file = Settings['default_xml_file'] if 'default_xml_file' in Settings else 'xmltv.xml'
  498. default_xml_socket = Settings['default_xml_socket'] if 'default_xml_socket' in Settings else 'xmltv.sock'
  499. default_icon_url = Settings['default_icon_url'] if 'default_icon_url' in Settings else None
  500. default_fetch_limit = Settings['default_fetch_limit'] if 'default_fetch_limit' in Settings else '2'
  501. default_rebroadcast = Settings['default_rebroadcast'] if 'default_rebroadcast' in Settings else 'y'
  502. default_episode = Settings['default_episode'] if 'default_episode' in Settings else 'y'
  503. default_verbose = Settings['default_verbose'] if 'default_verbose' in Settings else 'n'
  504. default_xmltvns = Settings['default_xmltvns'] if 'default_xmltvns' in Settings else 'n'
  505. except EnvironmentError:
  506. printError("epg2xml." + JSON_FILE_ERROR)
  507. sys.exit()
  508. except ValueError:
  509. printError("epg2xml." + JSON_SYNTAX_ERROR)
  510. sys.exit()
  511. parser = argparse.ArgumentParser(description = 'EPG 정보를 출력하는 방법을 선택한다')
  512. argu1 = parser.add_argument_group(description = 'IPTV 선택')
  513. argu1.add_argument('-i', dest = 'MyISP', choices = ['ALL', 'KT', 'LG', 'SK'], help = '사용하는 IPTV : ALL, KT, LG, SK', default = MyISP)
  514. argu2 = parser.add_mutually_exclusive_group()
  515. argu2.add_argument('-v', '--version', action = 'version', version = '%(prog)s version : ' + __version__)
  516. argu2.add_argument('-d', '--display', action = 'store_true', help = 'EPG 정보 화면출력')
  517. argu2.add_argument('-o', '--outfile', metavar = default_xml_file, nargs = '?', const = default_xml_file, help = 'EPG 정보 저장')
  518. argu2.add_argument('-s', '--socket', metavar = default_xml_socket, nargs = '?', const = default_xml_socket, help = 'xmltv.sock(External: XMLTV)로 EPG정보 전송')
  519. argu3 = parser.add_argument_group('추가옵션')
  520. argu3.add_argument('--icon', dest = 'icon', metavar = "http://www.example.com/icon", help = '채널 아이콘 URL, 기본값: '+ default_icon_url, default = default_icon_url)
  521. argu3.add_argument('-l', '--limit', dest = 'limit', type=int, metavar = "1-7", choices = range(1,8), help = 'EPG 정보를 가져올 기간, 기본값: '+ str(default_fetch_limit), default = default_fetch_limit)
  522. argu3.add_argument('--rebroadcast', dest = 'rebroadcast', metavar = 'y, n', choices = 'yn', help = '제목에 재방송 정보 출력', default = default_rebroadcast)
  523. argu3.add_argument('--episode', dest = 'episode', metavar = 'y, n', choices = 'yn', help = '제목에 회차 정보 출력', default = default_episode)
  524. argu3.add_argument('--verbose', dest = 'verbose', metavar = 'y, n', choices = 'yn', help = 'EPG 정보 추가 출력', default = default_verbose)
  525. args = parser.parse_args()
  526. if args.MyISP : MyISP = args.MyISP
  527. if args.display :
  528. default_output = "d"
  529. elif args.outfile :
  530. default_output = "o"
  531. default_xml_file = args.outfile
  532. elif args.socket :
  533. default_output = "s"
  534. default_xml_socket = args.socket
  535. if args.icon : default_icon_url = args.icon
  536. if args.limit : default_fetch_limit = args.limit
  537. if args.rebroadcast : default_rebroadcast = args.rebroadcast
  538. if args.episode : default_episode = args.episode
  539. if args.verbose : default_verbose = args.verbose
  540. if MyISP:
  541. if not any(MyISP in s for s in ['ALL', 'KT', 'LG', 'SK']):
  542. printError("MyISP는 ALL, KT, LG, SK만 가능합니다.")
  543. sys.exit()
  544. else :
  545. printError("epg2xml.json 파일의 MyISP항목이 없습니다.")
  546. sys.exit()
  547. if default_output :
  548. if any(default_output in s for s in ['d', 'o', 's']):
  549. if default_output == "d" :
  550. output = "display";
  551. elif default_output == "o" :
  552. output = "file";
  553. elif default_output == 's' :
  554. output = "socket";
  555. else :
  556. printError("default_output는 d, o, s만 가능합니다.")
  557. sys.exit()
  558. else :
  559. printError("epg2xml.json 파일의 output항목이 없습니다.");
  560. sys.exit()
  561. IconUrl = default_icon_url
  562. if default_rebroadcast :
  563. if not any(default_rebroadcast in s for s in ['y', 'n']):
  564. printError("default_rebroadcast는 y, n만 가능합니다.")
  565. sys.exit()
  566. else :
  567. addrebroadcast = default_rebroadcast
  568. else :
  569. printError("epg2xml.json 파일의 default_rebroadcast항목이 없습니다.");
  570. sys.exit()
  571. if default_episode :
  572. if not any(default_episode in s for s in ['y', 'n']):
  573. printError("default_episode는 y, n만 가능합니다.")
  574. sys.exit()
  575. else :
  576. addepisode = default_episode
  577. else :
  578. printError("epg2xml.json 파일의 default_episode항목이 없습니다.");
  579. sys.exit()
  580. if default_verbose :
  581. if not any(default_verbose in s for s in ['y', 'n']):
  582. printError("default_verbose는 y, n만 가능합니다.")
  583. sys.exit()
  584. else :
  585. addverbose = default_verbose
  586. else :
  587. printError("epg2xml.json 파일의 default_verbose항목이 없습니다.");
  588. sys.exit()
  589. if default_xmltvns :
  590. if not any(default_xmltvns in s for s in ['y', 'n']):
  591. printError("default_xmltvns는 y, n만 가능합니다.")
  592. sys.exit()
  593. else :
  594. addxmltvns = default_xmltvns
  595. else :
  596. printError("epg2xml.json 파일의 default_verbose항목이 없습니다.");
  597. sys.exit()
  598. if default_fetch_limit :
  599. if not any(str(default_fetch_limit) in s for s in ['1', '2', '3', '4', '5', '6', '7']):
  600. printError("default_fetch_limit 는 1, 2, 3, 4, 5, 6, 7만 가능합니다.")
  601. sys.exit()
  602. else :
  603. period = int(default_fetch_limit)
  604. else :
  605. printError("epg2xml.json 파일의 default_fetch_limit항목이 없습니다.");
  606. sys.exit()
  607. if output == "file" :
  608. if default_xml_file :
  609. sys.stdout = codecs.open(default_xml_file, 'w+', encoding='utf-8')
  610. else :
  611. printError("epg2xml.json 파일의 default_xml_file항목이 없습니다.");
  612. sys.exit()
  613. elif output == "socket" :
  614. if default_xml_socket :
  615. try:
  616. sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
  617. sock.connect(default_xml_socket)
  618. sockfile = sock.makefile('w')
  619. sys.stdout = sockfile
  620. except socket.error:
  621. printError(SOCKET_ERROR)
  622. sys.exit()
  623. else :
  624. printError("epg2xml.json 파일의 default_xml_socket항목이 없습니다.");
  625. sys.exit()
  626. getEpg()