root.py 10.6 KB
Newer Older
echel0n's avatar
echel0n committed
1
# ##############################################################################
2
3
4
#  Author: echel0n <[email protected]>
#  URL: https://sickrage.ca/
#  Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
echel0n's avatar
echel0n committed
5
#  -
6
#  This file is part of SiCKRAGE.
echel0n's avatar
echel0n committed
7
#  -
8
9
10
11
#  SiCKRAGE is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
echel0n's avatar
echel0n committed
12
#  -
13
14
15
16
#  SiCKRAGE is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
echel0n's avatar
echel0n committed
17
#  -
18
19
#  You should have received a copy of the GNU General Public License
#  along with SiCKRAGE.  If not, see <http://www.gnu.org/licenses/>.
echel0n's avatar
echel0n committed
20
# ##############################################################################
21
import base64
22
import datetime
23
import json
24
import os
25
from abc import ABC
26
27
28
from functools import cmp_to_key

from tornado.httputil import url_concat
29
from tornado.web import authenticated
30
31

import sickrage
32
from sickrage.core.databases.main import MainDB
33
from sickrage.core.enums import HomeLayout, HistoryLayout, PosterSortBy, PosterSortDirection
34
from sickrage.core.helpers import remove_article
35
36
from sickrage.core.media.util import series_image, SeriesImageType
from sickrage.core.tv.show.coming_episodes import ComingEpisodes, ComingEpsLayout, ComingEpsSortBy
37
from sickrage.core.tv.show.helpers import get_show_list, find_show
38
39
40
41
from sickrage.core.webserver import ApiHandler
from sickrage.core.webserver.handlers.base import BaseHandler


42
class RobotsDotTxtHandler(BaseHandler, ABC):
43
44
45
    def initialize(self):
        self.set_header('Content-Type', 'text/plain')

46
    def get(self, *args, **kwargs):
47
48
49
50
        """ Keep web crawlers out """
        return self.write("User-agent: *\nDisallow: /")


51
class MessagesDotPoHandler(BaseHandler, ABC):
52
53
54
    def initialize(self):
        self.set_header('Content-Type', 'text/plain')

55
    @authenticated
56
    def get(self, *args, **kwargs):
57
        """ Get /sickrage/locale/{lang_code}/LC_MESSAGES/messages.po """
58
59
        if sickrage.app.config.gui.gui_lang:
            locale_file = os.path.join(sickrage.LOCALE_DIR, sickrage.app.config.gui.gui_lang, 'LC_MESSAGES/messages.po')
60
61
62
63
64
            if os.path.isfile(locale_file):
                with open(locale_file, 'r', encoding='utf8') as f:
                    return self.write(f.read())


65
66
class APIBulderHandler(BaseHandler, ABC):
    @authenticated
67
    def get(self, *args, **kwargs):
68
        def titler(x):
69
            return (remove_article(x), x)[not x or sickrage.app.config.general.sort_article]
70
71
72

        episodes = {}

73
        for show_object in get_show_list():
74
75
            if show_object.series_id not in episodes:
                episodes[show_object.series_id] = {}
76
77

            for episode_object in show_object.episodes:
78
79
                if episode_object.season not in episodes[show_object.series_id]:
                    episodes[show_object.series_id][episode_object.season] = []
80

81
                episodes[show_object.series_id][episode_object.season].append(episode_object.episode)
82

83
84
        if len(sickrage.app.config.general.api_v1_key) == 32:
            apikey = sickrage.app.config.general.api_v1_key
85
86
87
        else:
            apikey = _('API Key not generated')

88
89
        api_commands = {}
        for command, api_call in ApiHandler(self.application, self.request).api_calls.items():
90
            api_commands[command] = api_call(self.application, self.request, **{'help': 1}).run()
91

92
93
94
95
        return self.render('api_builder.mako',
                           title=_('API Builder'),
                           header=_('API Builder'),
                           shows=sorted(get_show_list(), key=cmp_to_key(lambda x, y: titler(x.name) < titler(y.name))),
96
                           episodes=base64.b64encode(json.dumps(episodes).encode()).decode(),
97
98
99
100
                           apikey=apikey,
                           api_commands=api_commands,
                           controller='root',
                           action='api_builder')
101
102


103
104
class SetHomeLayoutHandler(BaseHandler, ABC):
    @authenticated
105
    def get(self, *args, **kwargs):
106
        layout = self.get_argument('layout', 'POSTER')
107

108
109
        if layout not in ('POSTER', 'SMALL', 'BANNER', 'SIMPLE', 'DETAILED'):
            layout = 'POSTER'
110

111
        sickrage.app.config.gui.home_layout = HomeLayout[layout]
112
        sickrage.app.config.save()
113
114
115
116
117

        # Don't redirect to default page so user can see new layout
        return self.redirect("/home/")


118
119
class SetPosterSortByHandler(BaseHandler, ABC):
    @authenticated
120
    def post(self, *args, **kwargs):
121
        sort = self.get_argument('sort', 'NAME')
122

123
124
        if sort not in ('NAME', 'DATE', 'NETWORK', 'PROGRESS'):
            sort = 'NAME'
125

126
        sickrage.app.config.gui.poster_sort_by = PosterSortBy[sort]
127
128
129
        sickrage.app.config.save()


130
131
class SetPosterSortDirHandler(BaseHandler, ABC):
    @authenticated
132
    def post(self, *args, **kwargs):
133
        direction = self.get_argument('direction', 'ASCENDING')
134

135
        sickrage.app.config.gui.poster_sort_dir = PosterSortDirection[direction]
136
137
138
        sickrage.app.config.save()


139
140
class SetHistoryLayoutHandler(BaseHandler, ABC):
    @authenticated
141
    def get(self, *args, **kwargs):
142
        layout = self.get_argument('layout', 'DETAILED')
143

144
145
        if layout not in ('COMPACT', 'DETAILED'):
            layout = 'DETAILED'
146

147
        sickrage.app.config.gui.history_layout = HistoryLayout[layout]
148
149
150
151

        return self.redirect("/history/")


152
153
class ToggleDisplayShowSpecialsHandler(BaseHandler, ABC):
    @authenticated
154
    def get(self, *args, **kwargs):
155
        show = self.get_argument('show')
156

157
        sickrage.app.config.gui.display_show_specials = not sickrage.app.config.gui.display_show_specials
158
        return self.redirect(url_concat("/home/displayShow", {'show': show}))
159
160


161
162
class SetScheduleLayoutHandler(BaseHandler, ABC):
    @authenticated
163
    def get(self, *args, **kwargs):
164
        layout = self.get_argument('layout', 'BANNER')
165

166
167
        if layout not in ('POSTER', 'BANNER', 'LIST', 'CALENDAR'):
            layout = 'BANNER'
168

169
170
        if layout == 'CALENDAR':
            sickrage.app.config.gui.coming_eps_sort = ComingEpsSortBy.DATE
171

172
        sickrage.app.config.gui.coming_eps_layout = ComingEpsLayout[layout]
173
174
175
176

        return self.redirect("/schedule/")


177
178
class ToggleScheduleDisplayPausedHandler(BaseHandler, ABC):
    @authenticated
179
    def get(self, *args, **kwargs):
180
        sickrage.app.config.gui.coming_eps_display_paused = not sickrage.app.config.gui.coming_eps_display_paused
181
182
183
        self.redirect("/schedule/")


184
185
class SetScheduleSortHandler(BaseHandler, ABC):
    @authenticated
186
    def get(self, *args, **kwargs):
187
        sort = self.get_argument('sort', 'DATE')
188

189
190
        if sort not in ('DATE', 'NETWORK', 'SHOW'):
            sort = 'DATE'
191

192
193
        if sickrage.app.config.gui.coming_eps_layout == ComingEpsLayout.CALENDAR:
            sort = 'DATE'
194

195
        sickrage.app.config.gui.coming_eps_sort = ComingEpsSortBy[sort]
196
197
198
199

        return self.redirect("/schedule/")


200
class ScheduleHandler(BaseHandler, ABC):
201
    @authenticated
202
    def get(self, *args, **kwargs):
203
        layout = self.get_argument('layout', None)
204

205
206
207
        next_week = datetime.datetime.combine(datetime.date.today() + datetime.timedelta(days=7),
                                              datetime.datetime.now().time().replace(tzinfo=sickrage.app.tz))

208
209
        today = datetime.datetime.now().replace(tzinfo=sickrage.app.tz)

210
        results = ComingEpisodes.get_coming_episodes(ComingEpisodes.categories, sickrage.app.config.gui.coming_eps_sort, False)
211

212
213
214
215
        return self.render('schedule.mako',
                           next_week=next_week,
                           today=today,
                           results=results,
216
                           layout=ComingEpsLayout[layout] if layout else sickrage.app.config.gui.coming_eps_layout,
217
218
219
220
221
                           title=_('Schedule'),
                           header=_('Schedule'),
                           topmenu='schedule',
                           controller='root',
                           action='schedule')
222
223


224
225
class QuicksearchDotJsonHandler(BaseHandler, ABC):
    @authenticated
226
    def post(self, *args, **kwargs):
227
        term = self.get_argument('term')
228

229
230
231
232
233
234
235
236
        shows = []
        episodes = []

        session = sickrage.app.main_db.session()

        for result in session.query(MainDB.TVShow).filter(MainDB.TVShow.name.like('%{}%'.format(term))).all():
            shows.append({
                'category': 'shows',
237
238
                'series_id': result.series_id,
                'series_provider_id': result.series_provider_id,
239
240
                'seasons': len(set([s.season for s in result.episodes])),
                'name': result.name,
241
                'img': sickrage.app.config.general.web_root + series_image(result.series_id, result.series_provider_id, SeriesImageType.POSTER_THUMB).url
242
243
244
            })

        for result in session.query(MainDB.TVEpisode).filter(MainDB.TVEpisode.name.like('%{}%'.format(term))).all():
245
            show_object = find_show(result.series_id, result.series_provider_id)
246
247
248
            if not show_object:
                continue

249
250
            episodes.append({
                'category': 'episodes',
251
252
                'series_id': result.series_id,
                'series_provider_id': result.series_provider_id,
253
                'episode_id': result.episode_id,
254
255
256
                'season': result.season,
                'episode': result.episode,
                'name': result.name,
257
258
                'show_name': show_object.name,
                'img': sickrage.app.config.general.web_root + series_image(result.series_id, result.series_provider_id, SeriesImageType.POSTER_THUMB).url
259
            })
260
261
262
263

        if not len(shows):
            shows = [{
                'category': 'shows',
264
265
                'series_id': '',
                'series_provider_id': '',
266
267
268
269
270
                'name': term,
                'img': '/images/poster-thumb.png',
                'seasons': 0,
            }]

271
        return self.write(json.dumps(shows + episodes))
272
273
274
275


class ForceSchedulerJobHandler(BaseHandler, ABC):
    @authenticated
276
    def get(self, *args, **kwargs):
277
278
279
280
        name = self.get_argument('name')

        service = getattr(sickrage.app, name, None)
        if service:
281
            job = sickrage.app.scheduler.get_job(service.name)
282
283
284
            if job:
                job.modify(next_run_time=datetime.datetime.utcnow(), kwargs={'force': True})
                sickrage.app.wserver.io_loop.add_timeout(datetime.timedelta(seconds=10), job.modify, kwargs={})