1 |
#!/usr/bin/python |
2 |
|
3 |
################################################################################ |
4 |
# # |
5 |
# Copyright (c) 2006 Andrew Pollock <me@andrew.net.au> All Rights Reserved # |
6 |
# # |
7 |
################################################################################ |
8 |
|
9 |
import socket |
10 |
import datetime |
11 |
|
12 |
class FrontendNotReady(Exception): |
13 |
pass |
14 |
|
15 |
|
16 |
class FrontendCmdFailure(Exception): |
17 |
pass |
18 |
|
19 |
|
20 |
class FrontendInvalidInput(Exception): |
21 |
pass |
22 |
|
23 |
|
24 |
class Frontend: |
25 |
"""Class for operating on a MythTV frontend""" |
26 |
|
27 |
def __init__(self, host, port=6546): |
28 |
self.host = host |
29 |
self.port = port |
30 |
self.ready = False |
31 |
self.socket = None |
32 |
# We might as well raise an exception at instantiation if |
33 |
# the frontend is unavailable |
34 |
self._connect() |
35 |
|
36 |
|
37 |
def _connect(self): |
38 |
"""Create a connection to the frontend""" |
39 |
|
40 |
self.socket = socket.socket() |
41 |
try: |
42 |
self.socket.connect((self.host, self.port)) |
43 |
except socket.error: |
44 |
raise FrontendNotReady("Unable to connect to frontend") |
45 |
if self.socket.recv(4096).splitlines()[-1] == '# ': |
46 |
self.ready = True |
47 |
|
48 |
|
49 |
def _sendcmd(self, cmd): |
50 |
"""Send a command to the frontend""" |
51 |
|
52 |
self._connect() |
53 |
if self.ready: |
54 |
self.socket.send("%s\r\n" % cmd) |
55 |
return self.socket.recv(4096).splitlines() |
56 |
|
57 |
|
58 |
def location(self): |
59 |
"""Return what location the front end is currently in""" |
60 |
|
61 |
result = self._sendcmd("query location")[0].split(" ") |
62 |
location = Location() |
63 |
location.where = result[0] |
64 |
if location.where == 'Playback': |
65 |
location.program = ProgramInfo() |
66 |
location.program.what = result[1] |
67 |
location.program.position = result[2] |
68 |
location.program.length = result[4] |
69 |
location.program.speed = result[5] |
70 |
location.program.chanid = result[6] |
71 |
recdate = result[7].split("T")[0].split("-") |
72 |
location.program.recdate = datetime.date(int(recdate[0]), int(recdate[1]), int(recdate[2])) |
73 |
rectime = result[7].split("T")[1].split(":") |
74 |
location.program.rectime = datetime.time(int(rectime[0]), int(rectime[1]), int(rectime[2])) |
75 |
if location.program.what == 'Recorded': |
76 |
try: |
77 |
location.program.title = self.recording(location.program.chanid, location.program.recdate.isoformat(), location.program.rectime.isoformat()) |
78 |
except FrontendNotReady: |
79 |
location.program.title = None |
80 |
elif location.where == 'PlaybackBox': |
81 |
pass |
82 |
elif location.where == 'MainMenu': |
83 |
pass |
84 |
|
85 |
return location |
86 |
|
87 |
|
88 |
def recording(self, chanid, recdate, rectime): |
89 |
"""Returns recording information for a specified recording""" |
90 |
|
91 |
result = self._sendcmd("query recording %s %sT%s" % |
92 |
(chanid, recdate, rectime))[0].split(" ") |
93 |
|
94 |
return " ".join(result[2:]) |
95 |
|
96 |
|
97 |
def pause(self): |
98 |
"""Pauses the playback""" |
99 |
|
100 |
result = self._sendcmd("play speed pause")[0] |
101 |
if result != "OK": |
102 |
#TODO(apollock): raise some sort of exception |
103 |
raise FrontendCmdFailure("Frontend said '%s' in response to 'play speed pause' command" % result) |
104 |
|
105 |
|
106 |
def play(self): |
107 |
"""Resumes playback""" |
108 |
result = self._sendcmd("play speed normal")[0] |
109 |
if result != "OK": |
110 |
raise FrontendCmdFailure("Frontend said '%s' in response to 'play speed normal' command" % result) |
111 |
|
112 |
|
113 |
def isPaused(self): |
114 |
"""Returns if the the frontend is paused or not""" |
115 |
loc1 = self.location() |
116 |
if loc1.where != 'Playback': |
117 |
return False |
118 |
else: |
119 |
loc2 = self.location() |
120 |
if loc2.where != 'Playback': |
121 |
return False |
122 |
else: |
123 |
return loc1.program.position == loc2.program.position |
124 |
|
125 |
def targets(self): |
126 |
"""Returns a list of targets that jump() accepts""" |
127 |
result = self._sendcmd("help jump") |
128 |
return [x.split(" ")[0] for x in result[3:]] |
129 |
|
130 |
|
131 |
def jump(self, target): |
132 |
"""Jumps to the specified location""" |
133 |
if target not in self.targets(): |
134 |
raise FrontendInvalidInput("Invalid jump target '%s'" % target) |
135 |
else: |
136 |
result = self._sendcmd("jump %s" % target)[0] |
137 |
if result != 'OK': |
138 |
raise FrontendCmdFailure("Frontend said '%s' in response to 'jump %s' command" % (result, target)) |
139 |
|
140 |
|
141 |
class Location: |
142 |
"""Container for where the frontend currently is""" |
143 |
|
144 |
def __init__(self): |
145 |
self.program = None |
146 |
self.where = None |
147 |
|
148 |
|
149 |
class ProgramInfo: |
150 |
"""Container for program information""" |
151 |
|
152 |
def __init__(self): |
153 |
pass |