1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
#
4
# Smewt - A smart collection manager
5
# Copyright (c) 2008 Ricard Marxer <email@ricardmarxer.com>
6
# Copyright (c) 2008 Nicolas Wack <wackou@gmail.com>
7
#
8
# Smewt is free software; you can redistribute it and/or modify
9
# it under the terms of the GNU General Public License as published by
10
# the Free Software Foundation; either version 3 of the License, or
11
# (at your option) any later version.
12
#
13
# Smewt is distributed in the hope that it will be useful,
14
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
# GNU General Public License for more details.
17
#
18
# You should have received a copy of the GNU General Public License
19
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
#
21
22
from smewt import SmewtException, SmewtUrl, Media, Metadata
23
from smewt.gui.collectionfolderspage import CollectionFoldersPage
24
from smewt.media import Series, Episode, Movie
25
from smewt.base import ImportTask, SubtitleTask, ActionFactory
26
from smewt.base.taskmanager import Task, TaskManager
27
from PyQt4.QtCore import SIGNAL, SLOT, QVariant, QProcess, QSettings, pyqtSignature
28
from PyQt4.QtGui import QWidget, QPushButton, QHBoxLayout, QVBoxLayout, QFileDialog, QSizePolicy
29
from PyQt4.QtWebKit import QWebView, QWebPage
30
from smewt.media import series, movie, speeddial
31
import logging
32
import time
33
from os.path import join, dirname, splitext
34
from smewt.taggers import EpisodeTagger, MovieTagger
35
from smewt.base import SmewtDaemon
36
37
log = logging.getLogger('smewt.gui.mainwidget')
38
39
minZoomFactor = 0.5
40
maxZoomFactor = 3.0
41
stepZoomFactor = 0.1
42
43
class MainWidget(QWidget):
44
    def __init__(self):
45
        super(MainWidget, self).__init__()
46
47
        self.collectionView = QWebView()
48
        self.collectionView.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks)
49
        #self.collectionView.page().setLinkDelegationPolicy(QWebPage.DelegateExternalLinks)
50
        self.setZoomFactor(QSettings().value('zoom_factor', QVariant(1.0)).toDouble()[0])
51
        self.connect(self.collectionView,  SIGNAL('linkClicked(const QUrl&)'),
52
                     self.linkClicked)
53
54
        layout = QVBoxLayout()
55
        layout.addWidget(self.collectionView)
56
57
        self.smewtd = SmewtDaemon()
58
        self.smewtd.taskManager.progressChanged.connect(self.progressChanged)
59
60
        self.setLayout(layout)
61
62
        self.history = []
63
        self.index = 0
64
        baseUrl = QSettings().value('base_url').toString()
65
        if baseUrl == '':
66
            baseUrl = 'smewt://media/speeddial/'
67
        self.setSmewtUrl(baseUrl)
68
69
        self.externalProcess = QProcess()
70
71
72
    def progressChanged(self, finished, total):
73
        if total == 0:
74
            self.refreshCollectionView()
75
76
    def quit(self):
77
        self.smewtd.quit()
78
79
    def setZoomFactor(self, factor):
80
        self.collectionView.page().mainFrame().setTextSizeMultiplier( factor )
81
82
    def zoomIn(self):
83
        zoomFactor = min(QSettings().value('zoom_factor', QVariant(1.0)).toDouble()[0] + stepZoomFactor, maxZoomFactor )
84
        QSettings().setValue('zoom_factor', QVariant( zoomFactor ) )
85
86
        self.setZoomFactor( zoomFactor )
87
88
    def zoomOut(self):
89
        zoomFactor = max(QSettings().value('zoom_factor', QVariant(1.0)).toDouble()[0] - stepZoomFactor, minZoomFactor)
90
        QSettings().setValue('zoom_factor', QVariant( zoomFactor ) )
91
92
        self.setZoomFactor( zoomFactor )
93
94
    def back(self):
95
        self.setSmewtUrl(None, self.index - 1)
96
97
    def forward(self):
98
        self.setSmewtUrl(None, self.index + 1)
99
100
    def speedDial(self):
101
        self.setSmewtUrl(SmewtUrl('media', 'speeddial/'))
102
103
    def setSmewtUrl(self, url, index = None):
104
        if index is not None:
105
            self.index = min(max(index, 0), len(self.history)-1)
106
            self.smewtUrl = self.history[self.index]
107
108
        else:
109
            if not isinstance(url, SmewtUrl):
110
                url = SmewtUrl(url = url)
111
112
            self.smewtUrl = url
113
114
            self.history[self.index+1:] = []
115
            self.history.append(url)
116
            self.index = len(self.history) - 1
117
118
        QSettings().setValue('base_url',  QVariant(unicode(self.smewtUrl)))
119
        try:
120
            self.refreshCollectionView()
121
        except Exception, e:
122
            import sys, traceback
123
            log.warning('Exception:\n%s' % ''.join(traceback.format_exception(*sys.exc_info())))
124
125
            # In case of error, return to the home screen
126
            log.warning('Returning to Speed Dial view')
127
            self.speedDial()
128
129
    def loadCollection(self):
130
        """Debug method."""
131
        filename = str(QFileDialog.getOpenFileName(self, 'Select file to load the collection'))
132
        self.collection.load(filename)
133
134
135
    def updateCollectionSettings(self, result):
136
        if result == 1:
137
            self.updateCollection()
138
139
    def updateCollection(self):
140
        self.smewtd.updateCollections()
141
142
    def rescanCollection(self):
143
        self.smewtd.rescanCollections()
144
145
    def selectSeriesFolders(self):
146
        d = CollectionFoldersPage(self,
147
                                  description = 'Select the folders where your series are.',
148
                                  collection = self.smewtd.episodeCollection)
149
        d.exec_()
150
151
    def selectMoviesFolders(self):
152
        d = CollectionFoldersPage(self,
153
                                  description = 'Select the folders where your movies are.',
154
                                  collection = self.smewtd.movieCollection)
155
        d.exec_()
156
157
158
    def mergeCollection(self, result):
159
        self.collection += result
160
161
    def refreshCollectionView(self):
162
        surl = self.smewtUrl
163
164
        if surl.mediaType == 'speeddial':
165
            html = speeddial.view.render(surl, self.smewtd.database)
166
            self.collectionView.page().mainFrame().setHtml(html)
167
168
        elif surl.mediaType == 'series':
169
            html = series.view.render(surl, self.smewtd.database)
170
            #open('/tmp/smewt.html',  'w').write(html.encode('utf-8'))
171
            #print html[:4000]
172
            self.collectionView.page().mainFrame().setHtml(html)
173
            # insert listener object for synopsis toggle button
174
            self.connect(self.collectionView.page().mainFrame(), SIGNAL('javaScriptWindowObjectCleared()'),
175
                         self.connectJavaScript)
176
177
        elif surl.mediaType == 'movie':
178
            html = movie.view.render(surl,  self.smewtd.database)
179
            #open('/tmp/smewt.html',  'w').write(html.encode('utf-8'))
180
            self.collectionView.page().mainFrame().setHtml(html)
181
            # insert listener object for checkboxes inside the JS environment
182
            self.connect(self.collectionView.page().mainFrame(), SIGNAL('javaScriptWindowObjectCleared()'),
183
                         self.connectJavaScript)
184
185
        else:
186
            raise SmewtException('MainWidget: Invalid media type: %s' % surl.mediaType)
187
188
    def connectJavaScript(self):
189
        self.collectionView.page().mainFrame().addToJavaScriptWindowObject('mainWidget', self)
190
191
    @pyqtSignature("bool")
192
    def toggleSynopsis(self, synopsis):
193
        self.smewtd.database.find_one('Config').displaySynopsis = synopsis
194
195
    @pyqtSignature("QString, bool")
196
    def updateWatched(self, title, watched):
197
        self.smewtd.database.find_one(Movie, title = unicode(title)).watched = watched
198
199
    @pyqtSignature("QString, QString, QString")
200
    def addComment(self, title, author, comment):
201
        g = self.smewtd.database
202
        movie = g.find_one(Movie, title = unicode(title))
203
        commentObj = g.Comment(metadata = movie,
204
                               author = unicode(author),
205
                               date = int(time.time()),
206
                               text = unicode(comment))
207
208
        self.refreshCollectionView()
209
210
    def linkClicked(self,  url):
211
        log.info('clicked on link %s', url)
212
        url = url.toEncoded()
213
214
        if url.startsWith('file://'):
215
            # FIXME: we should not use this anymore but a SmewtUrl with action = play
216
            log.warning('Deprecated api: links with file:// ...')
217
            action = 'smplayer'
218
            args = [ str(url)[7:] ]
219
            log.debug('launching %s with args = %s', (action, args))
220
            self.externalProcess.startDetached(action, args)
221
222
        elif url.startsWith('smewt://'):
223
            surl = SmewtUrl(url = url)
224
            if surl.mediaType:
225
                self.setSmewtUrl(surl)
226
227
            elif surl.actionType:
228
                ActionFactory().dispatch(self, surl)
229
230
            else:
231
                # probably feed watcher
232
                self.emit(SIGNAL('feedwatcher'))
233
234
        else:
235
            pass