#!/usr/bin/env python
# -*- coding: utf-8 -*-

import pygtk
pygtk.require("2.0")
import gtk
import gtkmozembed
from lxml import etree
import re
import webbrowser

APP_NAME = "TubeBrowser"
APP_VERSION = "0.2.0"
PROJECT_URL = "http://tubebrowser.sourceforge.jp/"
PROJECT_EMAIL = "tubebrowser-dev@lists.sourceforge.jp"

class TubeBrowserHtmlParser:
  def __init__(self, url):
    self.url = url
    self.method = None
    self.video_id = None
    self.title = None
    self.supported_sites = (
      # url pattern, method key
      ["^http://www\.youtube\.com/watch\?v=([^&]+)", "youtube"],
      ["^http://www\.tube8\.com/[^/]+/[^/]+/(\d+)/", "tube8"],
      ["^http://video\.fc2\.com/(?:a/)?content/[^/]+/(\w+)/", "fc2"],
      ["^http://www\.yourfilehost\.com/media\.php\?cat=video&file=([^&]+)",
       "yourfilehost"])

  def is_supported(self):
    for site in self.supported_sites:
      match = re.compile(site[0]).search(self.url)
      if (match):
        self.method = site[1]
        self.video_id = match.group(1)
        return True

    return False

  def get_content(self):
    if (self.method):
      content = getattr(self, "get_content_" + self.method)()
      return content
    else:
      return ""

  def get_title(self):
    return self.title

  def get_content_youtube(self):
    parser = etree.HTMLParser(encoding="utf-8")
    doc = etree.parse(self.url, parser)
    r = doc.xpath('//meta[@name="title"]/@content')
    self.title = r[0]
    r = doc.xpath('//div[@id="watch-video-container"]')
    content_script = etree.tostring(r[0], method="html")
    content = """
<html><body>
<style type="text/css">* {padding: 0; margin: 0;}</style>
%(content_script)s
</body></html>
"""
    return content % {"content_script": content_script
                      .replace("38\" + \"5", "100%")
                      .replace("64\" + \"0", "100%")}

  def get_content_tube8(self):
    parser = etree.HTMLParser()
    doc = etree.parse(self.url, parser)
    r = doc.xpath('//title')
    self.title = r[0].text
    r = doc.xpath('//div[@id="flvplayer"]')
    content_script = etree.tostring(r[0], method="html")
    content = """
<html><body>
<style type="text/css">* {padding: 0; margin: 0;}</style>
<script src="http://www.google.com/jsapi" language="javascript" type="text/javascript"></script>
<script language="javascript" type="text/javascript" >
google.load("jquery", "1.4.2");
google.load("swfobject", "2.2");
</script>
%(content_script)s
</body></html>
"""
    return content % {"content_script": content_script
                      .replace("autoPlay = '0'", "autoPlay = '1'")
                      .replace("640", "100%").replace("518", "100%")}

  def get_content_fc2(self):
    parser = etree.HTMLParser()
    doc = etree.parse(self.url, parser)
    r = doc.xpath('//title')
    self.title = r[0].text
    r = doc.xpath('//div[@class="video_player"]')
    content_script = etree.tostring(r[0], method="html")
    content = """
<html><body>
<style type="text/css">* {padding: 0; margin: 0;}</style>
%(content_script)s
</body></html>
"""
    return content % {"content_script": content_script
                      .replace("no_progressive=1", "no_progressive=0")
                      .replace("640", "100%").replace("392", "100%")}

  def get_content_yourfilehost(self):
    parser = etree.HTMLParser()
    doc = etree.parse(self.url, parser)
    self.title = self.video_id
    r = doc.xpath('//object[@id="objectPlayer"]')
    content_script = etree.tostring(r[0], method="html")
    content = """
<html><body>
<style type="text/css">* {padding: 0; margin: 0;}</style>
%(content_script)s
</body></html>
"""
    return content % {"content_script": content_script
                      .replace("autoStart=0", "autoStart=1")
                      .replace("470", "100%").replace("399", "100%")}

class TubeBrowser:
  def __init__(self):
    self.url = "about:";
    self.default_size = (340, 340) # width, height

    # mozembed renderer
    self.renderer = gtkmozembed.MozEmbed()
    self.renderer.set_flags(self.renderer.flags()|gtk.CAN_FOCUS)
    self.renderer.connect("location", self.url_changed)

    # address bar
    self.addressbar = gtk.Entry()
    self.addressbar.set_text(self.url)
    self.addressbar.connect("activate", self.open_addressbar, self.addressbar)
    self.addressbar.connect("drag_data_received", self.drag_data_received)
    self.addressbar.drag_dest_set(
      gtk.DEST_DEFAULT_MOTION, [('text/uri-list', 0, 0)], gtk.gdk.ACTION_COPY)

    # status message
    self.statusbar = gtk.Statusbar()
    self.statusbar_id = self.statusbar.get_context_id("main")

    self.window = gtk.Window()
    #self.window.set_size_request(self.default_size[0], self.default_size[1])
    self.window.set_default_size(self.default_size[0], self.default_size[1])
    self.window.connect("delete_event", gtk.main_quit)

    # window title
    self.window.set_title(APP_NAME)

    # window icon
    pixbuf = self.get_icon()
    if (pixbuf):
      self.window.set_icon(pixbuf)

    menubar = self.get_menubar(self.window)
    #message_id = self.statusbar.push(self.statusbar_id, "Ready")

    vbox = gtk.VBox()
    vbox.pack_start(menubar, False, True, 0)
    vbox.pack_start(self.addressbar, False, True, 0)
    vbox.pack_start(self.renderer, True, True, 0)
    vbox.pack_start(self.statusbar, False, True, 0)
    self.window.add(vbox)
    self.window.show_all()

    # default start page
    self.show_start_page()

  def url_changed(self, data=None):
    url = self.renderer.get_location()
    if (url != "about:" and url != self.url):
      self.addressbar.set_text(url)
      self.open_location(url)

  def get_menubar(self, window):
    "Create a main menu."
    # TODO: add 'Bookmarks' menu
    main_menu = """
<ui>
  <menubar name="MenuBar">
    <menu action="File">
      <menuitem action="Open" />
      <menuitem action="Quit" />
    </menu>
    <menu action="View">
      <menuitem action="Reload" />
      <menuitem action="Stop" />
      <menuitem action="Reset Size" />
    </menu>
    <menu action="Help">
      <menuitem action="Home Page" />
      <placeholder action="Sites holder">
        <menu action="Video Sites">
          <menuitem action="YouTube" />
          <menuitem action="Tube8" />
          <menuitem action="FC2 Video" />
          <menuitem action="YourFileHost" />
        </menu>
      </placeholder>
      <menuitem action="About" />
    </menu>
  </menubar>
</ui>
"""
    ui_manager = gtk.UIManager()
    accel_group = ui_manager.get_accel_group()
    window.add_accel_group(accel_group)

    # action group
    action_group = gtk.ActionGroup("MenuActionBase")
    action_group.add_actions(
      [("File", None, "_File"),
       ("View", None, "_View"),
       ("Help", None, "_Help")])
    ui_manager.insert_action_group(action_group, 0)

    action_group.add_actions(
      # name, stock id, label, accelerator, tooltip, callback
      [("Open", None, "_Open", "<control>L", None, self.focus_addressbar),
       ("Quit", None, "_Quit", None, None, gtk.main_quit),
       ("Reload", None, "_Reload", "F5", None, self.reload),
       ("Stop", None, "_Stop", None, None, self.stop),
       ("Reset Size", None, "Reset Size", None, None, self.reset_size),
       ("Home Page", None, "Home Page", None, None, self.open_homepage),
       ("Video Sites", None, "Video Sites", None, None, None),
       ("YouTube", None, "YouTube", None, None, self.open_sites),
       ("Tube8", None, "Tube8", None, None, self.open_sites),
       ("FC2 Video", None, "FC2 Video", None, None, self.open_sites),
       ("YourFileHost", None, "YourFileHost", None, None, self.open_sites),
       ("About", None, "_About", None, None, self.show_about_dialog)])

    ui_manager.add_ui_from_string(main_menu)
    return ui_manager.get_widget("/MenuBar")

  def get_icon(self):
    pixbuf = None
    icon_theme = gtk.icon_theme_get_default()
    icon_theme.append_search_path(".")
    #pixbuf = gtk.gdk.pixbuf_new_from_file("tubebrowser.svg")
    try:
      pixbuf = icon_theme.load_icon("tubebrowser", 48, 0)
    except:
      pass
    return pixbuf

  def drag_data_received(self, widget, context, x, y, selection, info, time):
    self.addressbar.set_text(selection.data)
    self.open_location(selection.data)

  def focus_addressbar(self, action, data=None):
    self.addressbar.grab_focus()

  def open_addressbar(self, widget, addressbar):
    self.open_location(addressbar.get_text())

  def open_location(self, location):
    self.url = location
    if (self.url == "about:"):
      self.show_start_page()
      return

    parser = TubeBrowserHtmlParser(self.url)
    if (parser.is_supported()):
      content = parser.get_content()
      title = parser.get_title()
      self.set_title(title)
      self.renderer.render_data(
        content, long(len(content)), self.url, "text/html")
      self.renderer.grab_focus()

    else:
      self.show_start_page()
      dialog = gtk.MessageDialog(
        None, gtk.DIALOG_MODAL, gtk.MESSAGE_WARNING, gtk.BUTTONS_OK,
        "The URL you entered is not supported.")
      dialog.set_title("Warning")
      dialog.run()
      dialog.destroy()

  def show_start_page(self):
    "Show the default start page."
    html = '<html><body bgcolor="#000000"></body></html>'
    self.renderer.render_data(html, long(len(html)), "about:", "text/html")
    self.set_title()
    self.renderer.grab_focus()

  def stop(self, action, data=None):
    self.addressbar.set_text("about:")
    self.open_location("about:")

  def reload(self, action, data=None):
    self.addressbar.set_text(self.url)
    self.open_location(self.url)

  def reset_size(self, action, data=None):
    "Reset the window size to default."
    self.window.resize(self.default_size[0], self.default_size[1])

  def open_homepage(self, action, data=None):
    webbrowser.open("http://tubebrowser.sourceforge.jp/")

  def open_sites(self, action, data=None):
    sites = {"YouTube": "http://www.youtube.com/",
             "Tube8": "http://www.tube8.com/",
             "FC2 Video": "http://video.fc2.com/",
             "YourFileHost": "http://www.yourfilehost.com/"}
    webbrowser.open(sites[action.get_name()])

  def show_about_dialog(self, action, data=None):
    "Show the 'About' dialog."
    dialog = gtk.AboutDialog()
    dialog.set_name(APP_NAME)
    dialog.set_version(APP_VERSION)
    dialog.set_comments("Web browser for video hosting sites.")
    dialog.set_website(PROJECT_URL)
    pixbuf = self.get_icon()
    if (pixbuf):
      dialog.set_logo(pixbuf)
    response = dialog.run()
    #dialog.hide()
    dialog.destroy()

  def set_title(self, title=None):
    if (title):
      self.window.set_title("%s - %s" % (title, APP_NAME))
    else:
      self.window.set_title(APP_NAME)

if __name__ == "__main__":
  app = TubeBrowser()
  gtk.main()
