From 5cae9c4009e6615b6ec0470b845a55fc91fb2893 Mon Sep 17 00:00:00 2001 From: wonipapa Date: Wed, 9 Nov 2016 17:31:12 +0900 Subject: [PATCH] =?UTF-8?q?=EB=B2=84=EC=A0=84=201.0.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SKCh.json | 2 +- epg2xml.py | 425 ++++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 325 insertions(+), 102 deletions(-) diff --git a/SKCh.json b/SKCh.json index c7d7710..fb515bb 100644 --- a/SKCh.json +++ b/SKCh.json @@ -164,7 +164,7 @@ {"Id":257,"KTCh":255,"SKCh":415,"LGCh":175,"Name":"소상공인방송","Source":"SK","ServiceId":428}, {"Id":258,"KTCh":31,"SKCh":29,"LGCh":null,"Name":"쇼핑엔T","Source":"SK","ServiceId":336}, {"Id":260,"KTCh":28,"SKCh":27,"LGCh":null,"Name":"신세계쇼핑","Source":"SK","ServiceId":339}, -{"Id":263,"KTCh":206,"SKCh":417,"LGCh":141,"Name":"아리랑TV","Source":"SKY","ServiceId":50}, +{"Id":263,"KTCh":206,"SKCh":417,"LGCh":141,"Name":"아리랑TV","Source":"SKY","ServiceId"50}, {"Id":264,"KTCh":186,"SKCh":352,"LGCh":114,"Name":"아시아경제","Source":"SK","ServiceId":622}, {"Id":265,"KTCh":22,"SKCh":3,"LGCh":20,"Name":"아임쇼핑","Source":"SK","ServiceId":332}, {"Id":266,"KTCh":138,"SKCh":106,"LGCh":149,"Name":"애니플러스","Source":"SK","ServiceId":377}, diff --git a/epg2xml.py b/epg2xml.py index 2c81108..6d2a898 100644 --- a/epg2xml.py +++ b/epg2xml.py @@ -6,129 +6,352 @@ import sys import urllib import json import datetime -import time +from bs4 import BeautifulSoup import codecs import socket import re -from xml.etree.ElementTree import Element, SubElement, dump from xml.sax.saxutils import escape import argparse -default_broadcast='all' -default_xml_filename='xmlepgtv.xml' -default_xml_socket='xmltv.sock' -default_chanfile='channellist.json' -default_fetch_limit=3 +reload(sys) +sys.setdefaultencoding('utf-8') -def channelList(ips='ALL'): - global channels - ch_channels=[] +__version__ = '1.0.1' - url = ('http://iptv.neo365.net/api/iptv/epg/channellist/%s' % ( ips ) ) - u = urllib.urlopen(url) - data = u.read() - j = json.loads(data) +# Set My Configuration +MyISP = 'ChangeThis' # 사용하는 IPTV선택 (ex :KT, LG, SK) +userid = 'ChangeThis' #tvheadend admin 아이디 (ex : admin) +userpw = 'ChangeThis' #tvheadedn admin 비밀번호 (ex : admin) +host = 'ChangeThis' #tvheadend 서버 내부 IP (ex: 192.168.0.2) +port = '9981' #tvheadend port +ChDelimiter = '-SD' #HD채널과 SD 채널 구분자 +offset = 500 # SD Channel Offset Number - SD 채널 사용시 HD 채널과 번호차 +iconurl = '' #TV channel icon url (ex : http://www.example.com/Channels) +default_xml_filename='xmltv.xml' # epg 저장시 기본 저장 이름 (ex: /home/tvheadend/xmltv.xml) +default_xml_socket='xmltv.sock' # External XMLTV 사용시 기본 소켓 이름 (ex: /home/tvheadend/xmltv.sock) +# Set My Configuration - channels = j["Channels"] - - for channel in channels: - ch_channelName = channel["ChannelName"] - ch_channelNo = channel["ChannelNo"] +hostinfo = userid + ':' + userpw + '@' + host + ':' + port - ch_channels.append('\t\n' % ( ch_channelNo)) - ch_channels.append('\t\t%s\n' % ( escape(ch_channelName)) ) - ch_channels.append('\t\t[%s] %s\n' % (ch_channelNo, escape(ch_channelName)) ) +# Set date +today = datetime.date.today() +nextday = today + datetime.timedelta(days=1) - for ch_detail in channel["Details"]: - ch_detailNo = ch_detail["ChannelNo"] - ch_detailName = ch_detail["ChannelName"] - ch_channels.append('\t\t%s\n' % ( escape(ch_detailName)) ) - ch_channels.append('\t\t[%s] %s\n' % (ch_channelNo, escape(ch_detailName)) ) +# Get Enabled Channel information +def getMyChannel(): + MyChannelNumber = [] + MyChannelurl = 'http://%s/api/channel/grid?all=1&dir=ASC&limit=999999999&sort=number&start=0' % (hostinfo) + MyChannels = json.loads(urllib.urlopen(MyChannelurl).read()) + for i, MyChannel in enumerate(MyChannels['entries']): + if MyChannel['enabled']: + if ChDelimiter in MyChannel['name']: + MyChannelNumber.append(MyChannel['number'] - offset) + else: + MyChannelNumber.append(MyChannel['number']) + return list(set(MyChannelNumber)) - ch_channels.append('\t\n') +# Get epg data +def getEpg(channelnumber): + Channelfile = os.path.dirname(os.path.abspath(__file__)) + '/' + MyISP + 'Ch.json' + ChannelInfos = [] + SiteEPG = [] #For epg.co.kr + with open(Channelfile) as f: # Read Channel Information file + Channeldata = json.load(f) + for chinfo in Channeldata: + for i in channelnumber: + if i == chinfo[MyISP+'Ch']: + ChannelInfos.append([chinfo['Id'], chinfo['Name'], chinfo['Source'], chinfo['ServiceId']]) + # Print Channel information + for ChannelInfo in ChannelInfos: + ChannelId = ChannelInfo[0] + ChannelName = escape(ChannelInfo[1]) + ChannelSource = ChannelInfo[2] + ChannelServiceId = ChannelInfo[3] + writeXML('\t' % (ChannelId)) + writeXML('\t\t%s' % (ChannelName)) + if iconurl: + writeXML('\t\t' % (iconurl, ChannelId)) + writeXML('\t') - for channel in channels: - for prog in channelDetail(channel["ChannelNo"]): - ch_channels.append(prog) - - return ch_channels -def channelDetail(channelId): - global channel - prog=[] - url = ('http://iptv.neo365.net/api/iptv/epg/channel/%s' % ( channelId )) - u = urllib.urlopen(url) - data = u.read() - j = json.loads(data) - channel = j["Channel"] - - for program in channel["Programs"]: - pr_programName = program["ProgramName"] - pr_actorName = program["Actor"] - pr_startTime = ("%s +9000" % ( program["StartTime"]) ) - pr_endTime = ("%s +9000" % ( program["EndTime"]) ) - pr_mainGenreName = program["Genre"] - pr_ratingCd = program["Rating"] - pr_episode = None - - if isinstance(pr_programName, unicode): - pr_programName = escape(pr_programName) - if isinstance(pr_mainGenreName, unicode): - pr_mainGenreName = escape(pr_mainGenreName) + # Print Program Information + for ChannelInfo in ChannelInfos: + ChannelId = ChannelInfo[0] + ChannelName = ChannelInfo[1] + ChannelSource = ChannelInfo[2] + ChannelServiceId = ChannelInfo[3] + if ChannelSource == 'EPG': + SiteEPG.append([ChannelId, ChannelName, ChannelSource, ChannelServiceId]) + elif ChannelSource == 'KT': + GetEPGFromKT(ChannelInfo) + elif ChannelSource == 'LG': + GetEPGFromLG(ChannelInfo) + elif ChannelSource == 'SK': + GetEPGFromSK(ChannelInfo) + elif ChannelSource == 'SKY': + GetEPGFromSKY(ChannelInfo) + GetEPGFromEPG(SiteEPG) - if pr_ratingCd > '0': - pr_ratingCd = u'%s세 이상 시청가' %(pr_ratingCd) - else: - pr_ratingCd = u'모든 연령 시청가' - - match=re.search('(?<=\()[\d]+', pr_programName) - - if match: - pr_episode = match.group()+u' 회' - - prog.append('\t\n' % ( pr_startTime, pr_endTime ,channelId)) - prog.append('\t\t%s\n' %(pr_programName)) - prog.append('\t\t%s\n' %(pr_mainGenreName)) - if pr_episode: - prog.append('\t\t%s\n' % pr_episode) - prog.append('\t\t\n\t\t\t%s\n\t\t\n' % pr_ratingCd) - prog.append('\t\n') - return prog +# Get EPG data from epg.co.kr +def GetEPGFromEPG(ChannelInfos): + pattern = "Preview\('(.*?)','(.*?)','(.*?)','(.*?)','(.*?)','(.*?)','(.*?)'\)\">.*?<\/a>(.*?)<\/td>" + p = re.compile(pattern) + ChannelInfo = [ChannelInfos[i:i+5] for i in range(0, len(ChannelInfos),5)] + for i in range(len(ChannelInfo)): + churl = '' + for j in range(len(ChannelInfo[i])): + churl += 'checkchannel%5B' + str(ChannelInfo[i][j][3]) + '%5D=' + str(ChannelInfo[i][j][0]) + '&' + url = 'http://schedule.epg.co.kr/php/guide/schedule_day_on.php?%snext=&old_sub_channel_group=110&old_sub_channel_group=110&old_top_channel_group=2&search_sub_category=&search_sub_channel_group=110&search_top_category=&search_top_channel_group=2&selectday=%s&selectday2=%s&weekchannel=&ymd=%s' % (churl, today, today, today) + u = urllib.urlopen(url).read() + data = unicode(u, 'euc-kr', 'ignore').encode('utf-8', 'ignore') + soup = BeautifulSoup(data,'lxml', from_encoding='utf-8') + html = soup.select('td > a[href^="JavaScript:ViewContent"]') + + for i, cell in enumerate(html): + td = cell.parent + epgdata = p.findall(str(td)) + programName = escape(epgdata[0][1]) + channelId = epgdata[0][2] + startTime, endTime = epgdata[0][3].split('<br>~') + startTime = str(today.year) + '/' + startTime + startTime = datetime.datetime.strptime(startTime, "%Y/%m/%d %p %I:%M") + startTime = startTime.strftime("%Y%m%d%H%M%S") + endTime = str(today.year) + '/' + endTime + endTime = datetime.datetime.strptime(endTime, "%Y/%m/%d %p %I:%M") + endTime = endTime.strftime("%Y%m%d%H%M%S") + category = escape(epgdata[0][4]) + actors = escape(epgdata[0][5]) + producer = escape(epgdata[0][6]) + image = epgdata[0][7] + checkRebroadcast = re.search('rebroadcast', image) + if not (checkRebroadcast is None) : + programName = programName + ' (재방송)' + checkRating = re.findall('7|12|15|19', image) + if len(checkRating) == 0: + rating = '모든 연령 시청가' + else: + rating = '%s세 이상 시청가' % (checkRating[0]) + + episode = None + checkEpisode = re.search('(?<=\()[\d]+', programName) + if not (checkEpisode is None): + episode = int(checkEpisode.group()) + + desc = programName + if episode : desc = desc + '\n회차 : ' + str(episode) + '회' + desc = desc + '\n장르 : ' + category + if actors : desc = desc + '\n출연 : ' + actors + if producer : desc = desc + '\n제작 : ' + producer + desc = desc + '\n등급 : ' + rating + programdata = {'channelId':channelId, 'startTime':startTime, 'endTime':endTime, 'programName':programName, 'desc':desc, 'actors':actors, 'producer':producer, 'category':category, 'episode':episode, 'rating':rating} + writeProgram(programdata) + +# Get EPG data from KT +def GetEPGFromKT(ChannelInfo): + channelId = ChannelInfo[0] + ServiceId = ChannelInfo[3] + + todayurl = 'http://tv.olleh.com/renewal_sub/liveTv/pop_schedule_week.asp?ch_name=&ch_no=%s&nowdate=%s&seldate=%s&tab_no=1' %(ServiceId, today, today) + nextdayurl = 'http://tv.olleh.com/renewal_sub/liveTv/pop_schedule_week.asp?ch_name=&ch_no=%s&nowdate=%s&seldate=%s&tab_no=1' % (ServiceId, nextday, nextday) + u1 = urllib.urlopen(todayurl).read() + data1 = unicode(u1, 'euc-kr', 'ignore').encode('utf-8', 'ignore') + soup1 = BeautifulSoup(data1,'lxml', from_encoding='utf-8') + + u2 = urllib.urlopen(nextdayurl).read() + data2 = unicode(u2, 'euc-kr', 'ignore').encode('utf-8', 'ignore') + soup2 = BeautifulSoup(data2,'lxml', from_encoding='utf-8') + + html = soup1.find('table', {'id':'pop_day'}).tbody.findAll('tr') + html1 = soup2.find('table', {'id':'pop_day'}).tbody.findAll('tr') + if not (html1 is None) and len(html1) > 0: + html2 = soup2.find('table', {'id':'pop_day'}).tbody.findAll('tr')[0] + else : + html2 = """ + + 00:00 + + + + + + + + """ + html2 = BeautifulSoup(html2,'lxml', from_encoding='utf-8').findAll('tr')[0] + html.append(html2) + + for row1, row2 in zip(html, html[1:]): + for cell1, cell2 in zip([row1.findAll('td')], [row2.findAll('td')]): + programName = escape(cell1[1].text).encode('utf-8') + startTime = cell1[0].text + startTime = str(today) + ' ' + startTime + startTime = datetime.datetime.strptime(startTime, "%Y-%m-%d %H:%M") + startTime = startTime.strftime("%Y%m%d%H%M%S") + endTime = cell2[0].text + if endTime == '00:00' : + endTime = str(nextday) + ' ' + endTime + else : + endTime = str(today) + ' ' + endTime + endTime = datetime.datetime.strptime(endTime, "%Y-%m-%d %H:%M") + endTime = endTime.strftime("%Y%m%d%H%M%S") + category = escape(cell1[4].text).encode('utf-8') + rating = escape(cell1[2].text).encode('utf-8') + if rating == 'all세 이상': + rating = '모든 연령 시청가' + else: + rating = rating + ' 시청가' + desc = programName + '\n장르 : ' + category + '\n등급 : ' + rating + actors = ''; + producer = ''; + episode = ''; + programdata = {'channelId':channelId, 'startTime':startTime, 'endTime':endTime, 'programName':programName, 'desc':desc, 'actors':actors, 'producer':producer, 'category':category, 'episode':episode, 'rating':rating} + writeProgram(programdata) + + +# Get EPG data from LG +def GetEPGFromLG(ChannelInfo): + pass + +# Get EPG data from SK +def GetEPGFromSK(ChannelInfo): + channelId = ChannelInfo[0] + ServiceId = ChannelInfo[3] + url = 'http://m.btvplus.co.kr/Common/Inc/IFGetData.asp?variable=IF_LIVECHART_DETAIL&pcode=|^|start_time=%s00|^|end_time=%s24|^|svc_id=%s'%(today.strftime("%Y%m%d"), today.strftime("%Y%m%d"), ServiceId) + u = urllib.urlopen(url).read() + data = json.loads(u, encoding='utf-8') + programs = data['channel']['programs'] + for program in programs: + programName = program['programName'] + if programName: + programName = escape(programName) + programName = programName.replace('(재)', ' (재방송)') + actors = program['actorName'] + if actors: actors = escape(actors) + producer = program['directorName'] + if producer: producer = escape(producer) + startTime = datetime.datetime.fromtimestamp(int(program['startTime'])/1000) + startTime = startTime.strftime("%Y%m%d%H%M%S") + endTime = datetime.datetime.fromtimestamp(int(program['endTime'])/1000) + endTime = endTime.strftime("%Y%m%d%H%M%S") + category = program['mainGenreName'] + if category: category = escape(category) + rating = program['ratingCd'] + if rating == '0': + rating = '모든 연령 시청가' + else : + rating = '%s세 이상 시청가' % (rating) + episode = None + checkEpisode = re.search('(?<=\()[\d]+', programName) + if not (checkEpisode is None): + episode = int(checkEpisode.group()) + desc = programName + if episode : desc = desc + '\n회차 : ' + str(episode) + '회' + desc = desc + '\n장르 : ' + category + if actors : desc = desc + '\n출연 : ' + actors + if producer : desc = desc + '\n제작 : ' + producer + desc = desc + '\n등급 : ' + rating + + programdata = {'channelId':channelId, 'startTime':startTime, 'endTime':endTime, 'programName':programName, 'desc':desc, 'actors':actors, 'producer':producer, 'category':category, 'episode':episode, 'rating':rating} + writeProgram(programdata) + +# Get EPG data from SKY +def GetEPGFromSKY(ChannelInfo): + channelId = ChannelInfo[0] + ServiceId = ChannelInfo[3] + url = 'http://www.skylife.co.kr/channel/epg/channelScheduleList.do?area=in&inFd_channel_id=%s&inairdate=%s&indate_type=now' % (ServiceId, today) + u = urllib.urlopen(url).read() + data = json.loads(u) + programs = data['scheduleListIn'] + + for program in programs: + programName = program['program_name'] + if programName: programName = escape(programName) + rebroadcast = program['rebroad'] + if rebroadcast == 'Y': programName = programName + ' (재방송)' + actors = program['cast'] + if actors: actors = escape(actors) + producer = program['dirt'] + if producer: producer = escape(producer) + startTime = program['starttime'] + endTime = program['endtime'] + category = program['program_category1'] + '-' + program['program_category2'] + if category: category = escape(category) + rating = escape(program['grade']) + if rating == '0': + rating = '모든 연령 시청가' + else : + rating = '%s세 이상 시청가' % (rating) + episode = program['episode_id'] + if episode : episode = int(episode) + description = program['description'] + if description: description = escape(description) + summary = program['summary'] + if summary: summary = escape(summary) + desc = programName + if episode : desc = desc + '\n회차 : ' + str(episode) + '회' + desc = desc + '\n장르 : ' + category + if actors : desc = desc + '\n출연 : ' + actors + if producer : desc = desc + '\n제작 : ' + producer + desc = desc + '\n등급 : ' + rating + if description: desc = desc + '\n' + description + if summary : desc = desc + '\n' + summary + + programdata = {'channelId':channelId, 'startTime':startTime, 'endTime':endTime, 'programName':programName, 'desc':desc, 'actors':actors, 'producer':producer, 'category':category, 'episode':episode, 'rating':rating} + writeProgram(programdata) + +# Write Program +def writeProgram(programdata): + channelId = programdata['channelId'] + startTime = programdata['startTime'] + endTime = programdata['endTime'] + programName = programdata['programName'] + desc = programdata['desc'] + actors = programdata['actors'] + producer = programdata['producer'] + category = programdata['category'] + episode = programdata['episode'] + rating = programdata['rating'] + print '\t' % (startTime, endTime,channelId) + print '\t\t%s' % (programName) + print '\t\t%s' % (desc) + if actors or producer: + print '\t\t' + if actors: print '\t\t\t%s' % (actors) + if producer: print '\t\t\t%s' % (producer) + print '\t\t' + print '\t\t%s' %(category) + if episode: + print '\t\t%s' % (episode) + print '\t\t\n\t\t\t%s\n\t\t' % (rating) + print '\t' + +# Write XML def writeXML(data): - if args.socket: - xmlfp.send(data.encode('utf-8')) - else: - xmlfp.write(data) + print data -parser = argparse.ArgumentParser() +parser = argparse.ArgumentParser(description=u'EPG 정보를 출력하는 방법을 결정') cmds = parser.add_mutually_exclusive_group(required=True) -cmds.add_argument('-w', dest='outputfile', metavar=default_xml_filename, nargs='?', const=default_xml_filename, help=u'저장할 파일이름') -cmds.add_argument('-s', dest='socket', metavar=default_xml_socket, nargs='?', const=default_xml_socket, help=u'xmltv.sock(External: XMLTV)로 EPG정보 전송') -opts = parser.add_argument_group(u'추가옵션') -opts.add_argument('-i', dest='ips', help=u'사용하는 망 : SK, KT, LG, ALL', default='ALL') +parser.add_argument('-v', '--version', action='version', version='%(prog)s ' + __version__) +cmds.add_argument('-d', '--display', action='store_true', help='EPG 정보 화면출력') +cmds.add_argument('-o', '--outfile', metavar=default_xml_filename, nargs='?', const=default_xml_filename, help='EPG 정보 저장') +cmds.add_argument('-s', '--socket', metavar=default_xml_socket, nargs='?', const=default_xml_socket, help='xmltv.sock(External: XMLTV)로 EPG정보 전송') args = parser.parse_args() +if args.outfile: + sys.stdout = codecs.open(args.outfile, 'w+', encoding='utf-8') +elif args.socket: + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.connect(args.socket) + sockfile = sock.makefile('w+') + sys.stdout = sockfile -global xmlfp +MyChannelNumber = getMyChannel() -if args.socket: - xmlfp = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - xmlfp.connect(args.socket) -elif args.outputfile: - xmlfp = codecs.open(args.outputfile, "w+", encoding="utf8") -else: - xmlfp = sys.stdout +writeXML('') +writeXML('') +writeXML('') +getEpg(MyChannelNumber) +writeXML('') -channels = [] -#channels = channelList(args.limit-1) -channels = channelList(args.ips) - -writeXML('\n\n') -writeXML('\n') - -for channel in channels: - writeXML(channel) - -writeXML('\n')