2011년 9월 29일 목요일

replyingtv - index.py

이 프로그램의 메인인 모듈인 index.py를 살펴보겠습니다.

# -*- coding: utf-8 -*-
'''
Created on 2011. 9. 14.

@author: Taejun Park

'''

from datetime import datetime, timedelta
import os
import logging

from google.appengine.api import memcache
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext import db
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext.db import djangoforms

#I made
import model
import getPrograms

#not yet attached
from django.utils import simplejson as json
 

def userLogging(self):
    """
    Args:
    self: page handler
    Returns:
    Logout(in) URL as a string, 'Login(out)'
    """
    if users.get_current_user():                                                        
        return users.create_logout_url(self.request.uri), 'Logout'
    else:
        return users.create_login_url(self.request.uri), 'Login'
    

def dateChanged(now):
    """
    Args:
    now : Datetime class
    Returns:
    True if changed, False if not    
    it checks wheather correct date was saved in the memcache/Parameter
    after it works, can use correct date guide
    """       
    
    today = now.date()
    
    programGuideDate = memcache.get("programGuideDate")
    
    #if memcache is empty
    if programGuideDate is None:
        parameter = model.Parameter.get_by_key_name(key_names='day')
        
        if parameter is None:   #if it is the first run
            model.Parameter(key_name='day', date=today ).put()
            if not memcache.add("programGuideDate", today): #save into memcache
                logging.error("Memcache set failed")
            return True
    
        programGuideDate = parameter.date
        
        if not memcache.add("programGuideDate", programGuideDate):  
            logging.error("Memcache set failed")
            
          
    if today > programGuideDate:    #if date changed
        #if now is after 4AM or more than 2days after
        if now.hour > 4 or today-programGuideDate > timedelta(1): 
            model.Parameter(key_name='day', date=today).put()
            if not memcache.add("programGuideDate", today):
                logging.error("Memcache set failed")
            return True
    #if not new day or tomorrow before 4am
    return False


def getBroadcastingProgramNow(broadcastingChannel):
    """
    Arg:
    broadcastingChannel : only KBS1 or KBS2 is supported now
    Return:
    ProgramGuide instance
    in this method, programLists: [program title+datetime] lists
    program = title+datetime+channel
    """    
    now = datetime.now()
    if dateChanged(now):  #if date changed, delete yesterday's program guide db with the same channel
        db.delete(model.ProgramGuide.gql("WHERE channel = :1", broadcastingChannel))
        
        #getPrograms returns [programtitle,datetime] as a list
        programLists = getPrograms.getPrograms(broadcastingChannel) #programs is list
        
        #parse programLists. the program name was got from KBS hompage so the encoding is euckr
        for program in programLists:
            model.ProgramGuide(key_name=program[0].decode('euckr', 'ignore'), programTime=program[1], channel=broadcastingChannel).put()
        
        #get if from db to match the type the same
        programs = model.ProgramGuide.gql("WHERE channel = :1 ORDER BY programTime ASC", broadcastingChannel)
        
        if not memcache.add(broadcastingChannel, programs):
            logging.error("Memcache set failed")
            
    else:   #check if the time pasts
        programs = memcache.get(broadcastingChannel)
        
        if programs is None:    #if memcache is empty, get it from db, add it to the memcache
            programs = model.ProgramGuide.gql("WHERE channel = :1 ORDER BY programTime ASC", broadcastingChannel)
            if not memcache.add(broadcastingChannel, programs):
                logging.error("Memcache set failed")
    
    #for ordered for clause. for more information, visit:
    #http://code.google.com/intl/ko-KR/appengine/docs/python/datastore/queries.html#Query_Cursors
    start_cursor = memcache.get("program_start_cursor")
    end_cursor = memcache.get("program_end_cursor")
    if start_cursor:
        programs.with_cursor(start_cursor = start_cursor)
    if end_cursor:
        programs.with_cursor(end_cursor = end_cursor)
    
    for program in programs:
        if program.programTime > now :  #if there's no program matches, it means there's no program now so return "화면조정"
            if not memcache.add("program_start_cursor", start_cursor):
                logging.error("Memcache set failed")    
            return program
    return None


class RecentCommentsPage(webapp.RequestHandler):
    """this class get 30 comments from db and match it for comments.html
    """
    def get(self):
        url, url_linktext = userLogging(self)
        comments = model.Comment.all().order('-written_datetime').fetch(30)
                    
        username = users.get_current_user()
                
        template_values={
                         'username':username,
                         'url':url,
                         'url_linktext':url_linktext,
                         'comments':comments,
                         }
        path=os.path.join(os.path.dirname(__file__), 'comments.html')
        self.response.out.write(template.render(path, template_values))
        
class MainPage(webapp.RequestHandler):
    """get which channel user want.
    then get what program is running now. get comments for the program
    send them to index.html
    """
    def get(self):
        #because there are not enough webpages, this program can only run over the KBSs.
        if self.request.path == '/2tv':
            channel = 'KBS2'
        else:
            channel = 'KBS1'    
        
        #get what program is running. probramNow programGuide Instance   
        programNow=getBroadcastingProgramNow(channel)
        
        if programNow is not None:        
            programInstance = model.Program.get_or_insert(key_name=programNow.key().name(), channel=channel)
            comments = model.Comment.gql("WHERE program = :program ORDER BY written_datetime DESC", program=programInstance).fetch(5)
            program = programNow.key().name()
        else:
            comments = None        
            program = None
        
        #make user signing up url
        url, url_linktext = userLogging(self)
        
        #HTML forms for POST
        form = ApplyingForm()
        
        username = users.get_current_user()

        template_values={
                         'channel':channel,
                         'head_title': '프로그램 목록',
                         'page_title': 'TV 프로그램 댓글',
                         'program': program,
                         'username': username,                                                
                         'url':url,
                         'url_linktext':url_linktext,   
                         'form': form,
                         'comments': comments                           
                         }
        path=os.path.join(os.path.dirname(__file__), 'index.html')
        self.response.out.write(template.render(path, template_values))
        
    #see http://code.google.com/intl/ko-KR/appengine/articles/djangoforms.html
    def post(self):
        #get POST requests
        data = ApplyingForm(data=self.request.POST)
        
        if data.is_valid():
            entity=data.save(commit=False)

            #get commenter: now this program saves email address of current user
            entity.commenter = users.get_current_user().email()
            
            entity.written_datetime =datetime.now()
            
            entity.written_via = 'replyingTV'  #later would be another platform
            
            #get program name from the web page, and get the model reference matches
            #first from the memcache, sencond from the db
            programNow = self.request.get('program')
            programInstance = memcache.get(programNow)
            if not programInstance:
                programInstance = model.Program.get_by_key_name(programNow)
            entity.program = programInstance
            
            try:         
                entity.put()    #save
            
            except :
                print "don't type that long, plz less than 500 bytes"
            finally:
            #redirect it to 2tv if it was from 2tv
                if self.request.get('channel') == 'KBS2':
                    self.redirect('/2tv', permenent=True)           
            
                self.redirect('')
            
        else:
            #redirect it to 2tv if it was from 2tv
            if self.request.get('channel') == 'KBS2':
                self.redirect('/2tv', permenent=True)           
        
            self.redirect('')
class ApplyingForm(djangoforms.ModelForm):
    """this class makes form for the Comment model
    see http://code.google.com/intl/ko-KR/appengine/articles/djangoforms.html
    """
    class Meta:
        model = model.Comment
        exclude=['commenter', 'written_datetime', 'program', 'written_via']
    
class TextPage(webapp.RequestHandler):
    """link to the replyingtv-program guide page
    """
    def get(self):
        self.redirect("http://tj850413.blogspot.com/", permanent=True)
        
def main():
    application = webapp.WSGIApplication([
                                          ('/about', TextPage),
                                          ('/2tv', MainPage),
                                          ('/comment', RecentCommentsPage),
                                          ('/.*', MainPage),
                                          ], debug=True)
    run_wsgi_app(application)
    
    
if __name__ == '__main__':
    main()

시간에 쫓겨 만들다보니 생각하던 것 보단 지저분한 코드가 나왔는데요, 하나하나 살펴보겠습니다.

def userLogging(self) - 앱엔진에서 제공하는 구글 id 로그인 모듈입니다. self클래스를 받아 로그인url과 문자열 login/logout을 리턴합니다. url은 나중에 index.html에서 로그인 url로써 쓰이고, 문자열login/logout은 역시 index.html에서 링크를 나타낼 때 쓰일 문자열입니다.

def dateChanged(now) - datetime인 now를 입력받아 편성표의 날짜가 바뀌었으면 True, 아니면 False를 리턴합니다.

def getBroadcastingProgramNow(broadcastingChannel) - broadCastingChannel을 입력받아 현재 채널의 방송중인 프로그램을 찾아  ProgramGuide 인스턴스를 리턴해줍니다.

class RecentCommentsPage(webapp.RequestHandler) - /comment 페이지의get메시지를 처리해줍니다. 코멘트를 위한 gql query를 보낸 후 최근의 30개만 보여줍니다.


class MainPage(webapp.RequestHandler) - 루트 페이지로 들어오는 get 및 post를 처리해줍니다. get 함수에선 Program 인스턴스를 등록해줍니다. post함수에선 html을 통해 들어온 새로운 comment를 등록해줍니다.


class ApplyingForm(djangoforms.ModelForm) - 장고의 모델폼을 상속하여, 폼을 등록하는데 사용하는 클래스입니다.


class TextPage(webapp.RequestHandler) - 이 블로그로 redirect해주는 클래스입니다.


def main() - WSGIApplication으로 각각의 페이지들을 유도해줍니다.

replyingtv - html파일들

replyingtv의 index.html입니다.
css등은 적용되지 않았고, template를 적용시키는 내용 외엔 복잡한 태그는 쓰이지 않았습니다.

<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-16" />	
		<title>{{ head_title }} - 현재 사용자: {{ username }}</title>
	</head>
	<body>
		{{ program }} 이 현재 방영되고 있습니다 | {{ channel }}
		<h1>{{ page_title }}</h1>
		<ul>{% for comment in comments %}
			<li>{{ comment.commenter }}
				{{ comment.written_datetime }} written via: {{ comment.written_via }}
				{{ comment.text }}
				<p/>
			</li>
			{% endfor %}
		</ul>
		{% if username and program %}
			<table border="1" align="center">
				<tr>
					<td width="100" align="center">사용자:</td> 
					<td>{{ username }}</td>
				</tr>
				<tr >
					<form method="post" action="." >
						{{ form.as_table }}
						<input type="hidden" name="program" value="{{ program }}">
					</form>
				</tr>
				<tr>
				</tr>
			</table>
		{% else %}{% if not program %}
			<p>현재 방송중인 프로그램을 얻을 수 없습니다</p>
		{% else %}		 
			<p>로그인 하세요</p>
		{% endif %}{% endif %}
		<a href="{{ url }}">{{ url_linktext }}</a> | 
		<a href="/comment">최근 댓글 페이지</a>
		<h2><a href="http://tj850413.blogspot.com/"> 이 사이트에 대하여</a></h2>
		
	</body>
</html>

앞부분에선 for문으로 comments를 통해 얻어온 내용들을 뿌려주며
아래쪽에선 user가 로그인해있고 program이 None이 아니면 comment입력 form을 형성해줍니다.
앱엔진에서 지원해주는 구글 로그인 url을 넣어주어 로그인했을 시엔 logout 링크가, 반대일때는 login이 뜨도록 하였습니다.
그 아래엔 최근 댓글들을 보여주는 링크가 있고
그 다음으론 이 블로그로 통하는 링크를 넣어주어습니다.

다음은 comments.html입니다.
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />	
		<title>최근 댓글 페이지 {{ username }}</title>
	</head>
	<body>
		<h1>최근에 등록 된 댓글 30개</h1>
			<ul>{% for comment in comments %}
			<li>{{ comment.text }} | 
				{{ comment.commenter }}
				{{ comment.program.key.name }}	
				{{ comment.written_datetime }} written via: {{ comment.written_via }}
				<p/>
			</li>

				{% endfor %}
			</ul>
		<a href="{{ url }}">{{ url_linktext }}</a> | 
		<a href="/">main page</a>
		
	</body>
</html>

여기에선 comment를 뿌려주는 일 외엔 별다른 설명할 부분이 없는 것 같습니다.

2011년 9월 30일 10시 40분 에러발생으로

갑자기 replyingtv가 에러가 발생해서 홈페이지를 이쪽으로 돌려놨습니다ㅠ
이번에도 로컬호스트에선 돌아가는데 앱엔진쪽엔 문제가 있네요... 고치고 있으니 나중에 다시 들려주세요ㅠㅠㅠ

http://replyingtv.appspot.com/2tv
를 들리시면 현재 상태를 아실 수 있습니다

2011년 9월 28일 수요일

replyingtv - model.py

replyingtv의 소스코드 중 모델 선언부분인 model.py를 살펴보겠습니다.

# -*- coding: utf-8 -*-

'''
Created on 2011. 9. 8.

@author: Park
'''

from google.appengine.ext import db 


class Program(db.Model):
    """this class saves the program titles, channel and the date which
    the program instance made
    """
    channel = db.StringProperty()
    date = db.DateTimeProperty(auto_now_add=True)

class Comment(db.Model):
    """this class saves comments
    program references the Program class.
    written_via is for the multi-platform extension.(ex i-phone, LGtv etc 
    """
    #if there would be another platform, 'commenter' should be changed as string or etc for many format
    commenter = db.EmailProperty()
    written_datetime = db.DateTimeProperty()
    program = db.ReferenceProperty(Program)
    written_via = db.StringProperty()
    text = db.StringProperty()

class Parameter(db.Model):
    """this class is for saving some parameters which need to run
    the whole program.
    2011.09.29: now only has date.
    """
    date = db.DateProperty()
    
class ProgramGuide(db.Model):
    """it saves the channel guide today. channel and program time, and
    the title as a key_name. 
    """
    programTime = db.DateTimeProperty()
    channel = db.StringProperty(multiline=True)   #ex) kbs1, kbs2 ...


별다른 어려운 부분은 없지만, Parameter 클래스는 변수 몇가지를 저장하기 위해 모델을 만들어 쓰게 돼서, 다른 방법이 없을까 하는 생각도 들었습니다만 뾰족한 방법을 모르겠네요

2011년 9월 27일 화요일

replyingtv.appspot.com 글자가 깨지던 이유

 kbs에서 읽어왔던 프로그램 제목들을 제대로 디코딩했어야 했는데, 그걸 제대로 하지 못했었습니다. 이거 해결하는 데 하루 정도 걸린 것 같네요. 그래도 스스로 알아낸 것 같아 기분이 좋습니다.

 kbs 편성표 웹페이지 헤더엔 당당히 euc-kr이라고 적혀있었는데 그걸 왜 여태 신경쓰지 못했었을까요...
 파이썬 유니코드 페이지에 들려 윈도 시스템에선 'mbcs'로 디코딩하면 된다는 듯이 써있어 개인 컴퓨터로 앱엔진 런쳐를 돌려서 해봤을 땐 됐었는데, 또 앱엔진 사이트는 윈도 시스템은 당연히 아니니 안됐었습니다. 그래서 괜히 어떤 OS인지 뒤적거리다가 이것 저것 적다가, 또 따옴표 빼먹고 적었다가 여러가지 다 하다 드디어 한글 뜨게 됐습니다ㅠ..

 누구신진 몰라도 들려주신 분 감사합니다.

 많은 걸 배워서 기분 좋네요 ㅎㅎ

replyingtv - getPrograms.py

 안녕하세요, replyingTV의 소스코드에 별다른 보고서를 첨부해 보내지 않은 걸 나중에 깨달아 이렇게 웹에 올립니다. 여기까지 들어오셔서 읽으실지 어떨지 모르겠는데요ㅠ 어쨌든 간단하게나마 설명하겠습니다.


# -*- coding: utf-8 -*-
'''
Created on 2011. 9. 14.

@author: Taejun Park

'''


import urllib
from datetime import datetime

def getHtml(url):
    """
    read the html of the channel guide page
    """
    
    sock = urllib.urlopen(url)
    htmlSource = sock.read()
    sock.close()
    return htmlSource


def getPrograms(broadcastingChannel):
    """
    Args:
    broadcastingChannel: KBS1 or KBS2,
        "http://www.kbs.co.kr/plan_table/channel/1tv/index.html" 
        or "http://www.kbs.co.kr/plan_table/channel/2tv/index.html"
    
    Returns:
    List of [program:time], program is string(utf-16) and time datetime.time
    
    this "getPrograms" is only suit for kbs. it parses program guide as a list
    while parsing, there is some problem.
    one type has got <a> tag which I tried to solve first(type1),but there are some
    programs which don't have web sites(type2).
    for them, this program checks character after <td> opening tag next to the time. 
    
    html samples:
    type1 -
    <td height="25" align="center" class="gd_list_date">17:35</td>
    <td height="25"><a href="http://www.kbs.co.kr/1tv/enter/openconcert/index.html" target="_blank">대장경 천년 세계문화  축전기념  열린음악회  [경남 합천  군민생활   체육공원  ] </a>
    
    type2 -
    <td height="25" align="center" class="gd_list_date">19:00</td>
    <td height="25">KBS 뉴스  <img src="http://img.kbs.co.kr/cms/plan_table/channel/images/icon_hd.jpg" width="13" height="11" hspace="2">
    """
                
    #get html source
    if broadcastingChannel is "KBS1":
        htmlSource = getHtml("http://www.kbs.co.kr/plan_table/channel/1tv/index.html")
    elif broadcastingChannel is "KBS2":
        htmlSource = getHtml("http://www.kbs.co.kr/plan_table/channel/2tv/index.html")
    
    #find the mark which marks the beginning of the channel guide
    #every program has this class property, so it will be the mark for each program
    markOfProgram = 'class="gd_list_date"'  #20 chars
    
    #programStartingPoint is Integer, and other points as well
    programStartingPoint = htmlSource.find(markOfProgram)
    
    #if there's no programStartingPoint, you should revise the markOfProgram
    if programStartingPoint == -1:
        print 'you need to arrange the startingPoint'
    
    #List to return
    programList = []
    now = datetime.now()
    
    while programStartingPoint != -1:     #do it until there's no more program
        
        #20chars + "<", and time has 5 chars (ex. 12:30
        programTime = htmlSource[programStartingPoint+21:programStartingPoint+26]
        
        #I found that after 60 chars, there begins <a> tag for type 1 or title for type 2 
        if htmlSource[programStartingPoint + 60] == '<': #for type 1        

            #title string is: <a >HERE</a>.  between the <a> starting and end tags.
            aTagOpeningEndingPoint = htmlSource[programStartingPoint+60:].find(">") + programStartingPoint+60
            aTagClosingStartingPoint = htmlSource[aTagOpeningEndingPoint:].find("<") + aTagOpeningEndingPoint
            title = htmlSource[ aTagOpeningEndingPoint+1 : aTagClosingStartingPoint ]
       
        else:   #for type 2
            #count characters until program title be found, and then find < tag
            aTagClosingStartingPoint = htmlSource[programStartingPoint+60:].find("<") + programStartingPoint+60
            title = htmlSource[programStartingPoint+60:aTagClosingStartingPoint]
                
        
        #before save, make title to be utf-16, make programTime as Datetime class
        if programTime < '04:01':   #if the programTime is for tomorrow
            programTimeFormatted = datetime.strptime(programTime, "%H:%M")
            #remove whitespaces from title
            programList.append([title.strip(), now.replace(day=now.day+1, hour=programTimeFormatted.hour, minute=programTimeFormatted.minute)])
            
        else:
            programTimeFormatted = datetime.strptime(programTime, "%H:%M")
            #remove whitespaces from title
            programList.append([title.strip(), now.replace(hour=programTimeFormatted.hour, minute=programTimeFormatted.minute)]) 
              
        #reset programStartingPoint
        programStartingPoint = htmlSource[aTagClosingStartingPoint:].find(markOfProgram)
        if programStartingPoint != -1: #-1 if there's no more program -> exit while
            programStartingPoint = programStartingPoint + aTagClosingStartingPoint
    
    return programList

 이 프로그램은 그나마 주석을 적당히 달았다고 생각하는데요, getHtml 함수가 html 파일을 받아오고, getPrograms 함수가 파싱작업을 거쳐 프로그램들의 리스트를 리턴하게 됩니다.
 특별히 복잡한 부분은 없고, kbs의 편성표 페이지를 보고 이런 저런 조건을 만들었습니다. 어떤 페이지는 링크가 달려있고 어떤 건 그렇지 않아 그에 맞춰 작성했고, 방송시간은 datetime 클래스로 저장하였습니다. 편성표에서 4시 이하의 시간은 다음날 방송으로 처리하도록 했습니다.

Replying TV에 대하여



) 애플리케이션의 용도 방송 프로그램 댓글서비스 
- 사람들은 방송에 대한 평가, 의견을 제작진에게 전달하기 위해 방송사의 프로그램 게시판을 이용합니다. 하지만 대체로 폐쇄적이고(홈페이지 가입 요구), 접근성이 매우 떨어져, 많은 사람들이 굳이 가입을 하면서까지 의견을 남기고 싶어하진 않습니다.
 대신 많은 사람들은 방송을 시청한 , 다른 사람들과 공감을 나누기 위해 네이버, 다음, 네이트 등의 뉴스게시판의 방송기사에 수백, 수천개의 댓글을 답니다. 포털사이트의 뉴스 게시판들이 따로 특별한 기능을 제공하는 것은 아니지만, 대신 그들은 뛰어난 접근성을 가지고 있기에 많은 사람들이 이용하고, 그로 인해 타인의 의견을 보려는 사람들과 자신의 생각을 적으려는 사람들로 항상 넘쳐납니다. 바로 뛰어난 접근성을 생각하여 생각해낸 것이 서비스입니다.
 TV 의견을 적기 위해 컴퓨터 앞에 앉아 포털사이트에 접속한다, 뉴스를 찾고 로그인을 의견을 적는다. 방송국의 게시판을 찾아다니는 것보단 충분히 쉬운 프로세스이지만, 스마트TV 이용한다면 과정을 훨씬 간단하게 줄일 있습니다. TV 켜서 본다, 보다가 방송에 대해 쓰고 싶은 말이 있으면 리모콘의 키패드로 의견을 적는다. 이런 활용을 위해서 스마트TV 나온 아닐까요?
 스마트TV 이용해, 방송을 시청하는 동시에 자신의 의견을 적고, 다른 사람이 올린 생각들을 있다면, 인터넷 뉴스 게시판과 비교해 접근성은 비교할 없을 정도로 올라가고, 방송국으로선 능동적인 시청으로 인해 사람들을 TV 앞에 붙잡아놓을 있으며, 더불어 인터넷을 통해 시청자 의견을 올리는 익숙하지 않은 주부시청자들에게도 하나의 재미난 놀이거리로 여겨질 있을 거라 생각합니다. 원래대로라면 TV 떠안고 갔어야 인터넷 뉴스 게시판에 흡수되어버린 시청자들의 의견을 다시 TV 불러들이는 것입니다. TV 중심의, 새로운 형태의 포탈을 만들 있다고 생각합니다.

) 사용자 시나리오

  애플리케이션엔 가지 타입의 실행화면이 있습니다. 하나는 TV방송 중심의 화면이고, 다른 하나는 이용자들의 댓글에 좀더 중점을 화면입니다. 하나씩 그림으로 보여드리겠습니다.









1)    화면-1 실행장면


  번째 화면은 이런 식의 화면 위에 떠있는 반투명 위젯 같은 형식입니다. 방식은 예전에 케이블에서 유행하던, 프로그램을 진행하는 VJ 생방송으로 시청자와 문자를 주고받는 모습을 떠올리며 구상했습니다. 평소 저런 곳에 문자를 보내는 바보 같다고 생각하면서도, 또한 친구들과 놀러 가서 TV 돌렸을 그런 문자를 보여주는 방송이 있어 친구 이름 나오게 한번 보내봤었는데요, 저처럼 자기 이름이라던가 친구 이름, 자신이 글을 TV 띄워보고 싶은 누구나 해보고 싶은 일일 것입니다. 저는 서비스가 이런 욕구를 충족시켜줄 있을 거라 생각합니다. 글이 화면을 벗어날 경우엔 글이 표시되고 5 후에 부드럽게 아래에서 위쪽으로 나머지 글을 스크롤해주고, 10 단위로 서버에 확인해 단위로 갱신하여줍니다.

 

2) 화면-1 댓글 입력 장면

 사용자가 글을 입력하는 순간의 화면입니다. 크게 화면을 벗어나지 않고 리모콘의 특정 버튼으로 화면 입력 창으로 전환하여 줍니다. 입력 또한 리모콘의 키패드를 이용해 즉석에서 입력하도록 해줍니다. 입력이 끝나 리모콘의 확인 버튼을 누르면, 서버의 해당 방송의 DB 글이 올라가 전국의 애플리케이션을 사용하며 해당 방송을 보는 시청자들에게 전달하도록 합니다.
 화면-1 사용 시나리오는 다음과 같습니다
  1.  방송을 시청하며 애플리케이션을 실행한다. 실행되면 현재 화면에서 나오고 있는 방송의 실시간으로 올라오는 댓글을 화면 아래의 대화창으로 보여준다. 대화창의 글은 10초마다 갱신된다.  (그림1)
  2.  시청자가 글을 작성하고 싶은 경우, 스마트 리모콘의 특정 버튼으로 화면을 전환하여 이용하여 (그림2) 화면으로 전환한다. 입력 확인 버튼을 누르면 다시 (그림1) 화면으로 전환되고, 잠시 자신이 작성한 글을 화면 전국의 동일한 서비스를 이용하는 사람들이 공유할 있다.
 다음으로 번째 화면을 보여드리겠습니다.
 



그림3) 화면-2 실행장면

  위의 그림은 다른 형태의 화면을 실행한 장면입니다. 화면-1에서 리모콘의 특정 버튼 입력으로 화면-2 전환하게 됩니다. 화면-1에선 방송시청을 주요 목적으로 뒀었지만, 화면은 시청자들의 의견에 무게를 형태입니다.
  화면 오른쪽으론 5여개 정도의 댓글을 동시에 있습니다. 리모콘의 화살표 이전/다음 버튼 등으로 이전글, 다음글 등으로 전환이 가능하고, 글이 조금 길어 중간에 잘린 경우엔, 위의 (그림3)3번째 글과 같이 포커스를 맞춘 경우엔 나머지 글이 스크롤되어 나머지 글도 있게 됩니다. 화면 역시 10 마다 서버에서 글을 받아오게 되는데, 만약 글이 있는 경우엔 아래에 작게 글을 알리는 글씨가 뜨게 됩니다(그림4).
   방송 화면의 아래쪽으로는, 방송국의 게시판 혹은 광고 등을 위치시킵니다. 지금 그림은 방송국의 게시판을 위치시켰는데, 이럴 경우 시청자 의견이 중요한 방송이라면, 많은 시청자들의 의견을 모을 있을 거라 생각합니다(물론 시청자 의견을 싫어하는 제작자도 많이 있을 거라 생각합니다). 추후 드라마 등장 상품의 쇼핑정보 등을 연계한다거나, 간접광고로 보여줄 없는 제품의 광고 등을 올린다면, 직접적으로도 수익을 만들 있는 실용적인 서비스가 거라 생각합니다. 사실 대부분의 시중 스마트TV 상당히 크기 때문에, 방송 아래 쪽의 화면을 분할하여 절반가량은 방송국에서 제공하는 웹사이트로(광고든 홈페이지든), 그리고 나머지 절반의 범위는 광고로 싣는 방법도 좋을 같습니다.


 4)화면-2에서 글이 올라온 경우의 장면


화면-2 시나리오입니다.
1. 화면-1 상태에서 리모콘의 전환 기능을 담당하는 버튼을 선택해 화면-2 바꿉니다. 이용자는 오른쪽의 댓글들을 보며 다른 사람도 방송을 보며 자신과 같은 생각을 하는지 확인합니다. 중간에 길어서 내용이 나오지 않은 글이 있을 경우, 리모콘의 화살표로 커서를 옮겨 놓으니 글의 나머지 부분이 스크롤되어 마저 있습니다.
3. 댓글을 작성하기 위해 리모콘의 특정 버튼을 누르니 작성 화면으로 변합니다. 기존의 글들은 아래쪽으로 밀리고 대신 위쪽엔 리모콘의 키패드로 입력 가능한 입력창이 등장합니다(그림6).
2. 이용 시청자 게시판에 글을 올리고 싶을 경우, 화면 아래의 웹브라우저를 통해 확인합니다. 어떤 특정 장면에선 아래 화면이 제품의 광고로 전환됩니다. 구입하고 싶었던 제품이기에 아래 광고로 커서를 옮겨 선택하니 제품을 파는 웹페이지로 연결이 됩니다(그림5).



5)화면-2에서 방송과 연계된 광고가 나오는 모습



6)화면-2에서 글을 작성하는 모습

function foo()
{
}