Completed
Push — dev ( 1a6558...8d703f )
by Darko
07:11
created

Videos::getTitleLoose()   B

Complexity

Conditions 7
Paths 21

Size

Total Lines 32
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 21
c 1
b 0
f 0
dl 0
loc 32
ccs 0
cts 18
cp 0
rs 8.6506
cc 7
nc 21
nop 3
crap 56
1
<?php
2
/**
3
 * This program is free software: you can redistribute it and/or modify
4
 * it under the terms of the GNU General Public License as published by
5
 * the Free Software Foundation, either version 3 of the License, or
6
 * (at your option) any later version.
7
 *
8
 * This program is distributed in the hope that it will be useful,
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 * GNU General Public License for more details.
12
 *
13
 * You should have received a copy of the GNU General Public License
14
 * along with this program (see LICENSE.txt in the base directory.  If
15
 * not, see:
16
 *
17
 * @link      <http://www.gnu.org/licenses/>.
18
 * @author    niel
19
 * @copyright 2015 nZEDb
20
 */
21
22
namespace Blacklight\processing;
23
24
use App\Models\TvInfo;
25
use App\Models\Video;
26
use App\Models\VideoAlias;
27
use Illuminate\Support\Facades\Cache;
28
29
/**
30
 * Parent class for TV/Film and any similar classes to inherit from.
31
 */
32
abstract class Videos
33
{
34
    // Video Type Identifiers
35
    protected const TYPE_TV = 0; // Type of video is a TV Programme/Show
36
    protected const TYPE_FILM = 1; // Type of video is a Film/Movie
37
    protected const TYPE_ANIME = 2; // Type of video is a Anime
38
39
    /**
40
     * @var bool
41
     */
42
    public $echooutput;
43
44
    /**
45
     * @var array	sites	The sites that we have an ID columns for in our video table.
46
     */
47
    private static $sites = ['imdb', 'tmdb', 'trakt', 'tvdb', 'tvmaze', 'tvrage'];
48
49
    /**
50
     * @var array Temp Array of cached failed lookups
51
     */
52
    public $titleCache;
53
54
    public function __construct(array $options = [])
55
    {
56
        $defaults = [
57
            'Echo'     => false,
58
            'Settings' => null,
59
        ];
60
        $options += $defaults;
61
62
        $this->echooutput = ($options['Echo'] && config('nntmux.echocli'));
63
        $this->titleCache = [];
64
    }
65
66
    /**
67
     * Main processing director function for scrapers
68
     * Calls work query function and initiates processing.
69
     *
70
     * @param      $groupID
71
     * @param      $guidChar
72
     * @param      $process
73
     * @param bool $local
74
     */
75
    abstract protected function processSite($groupID, $guidChar, $process, $local = false): void;
76
77
    /**
78
     * Get video info from a Video ID and column.
79
     *
80
     * @param string  $siteColumn
81
     * @param int $videoID
82
     *
83
     * @return array|false    False if invalid site, or ID not found; Site id value otherwise.
84
     */
85
    protected function getSiteIDFromVideoID($siteColumn, $videoID)
86
    {
87
        if (\in_array($siteColumn, self::$sites, false)) {
88
            $result = Video::query()->where('id', $videoID)->first([$siteColumn]);
89
90
            return $result !== null ? $result[$siteColumn] : false;
91
        }
92
93
        return false;
94
    }
95
96
    /**
97
     * Get TV show local timezone from a Video ID.
98
     *
99
     * @param int $videoID
100
     *
101
     * @return string Empty string if no query return or tz style timezone
102
     */
103
    protected function getLocalZoneFromVideoID($videoID): string
104
    {
105
        $result = TvInfo::query()->where('videos_id', $videoID)->first(['localzone']);
106
107
        return $result !== null ? $result['localzone'] : '';
108
    }
109
110
    /**
111
     * Get video info from a Site ID and column.
112
     *
113
     *
114
     * @param $siteColumn
115
     * @param $siteID
116
     * @return bool|int
117
     */
118
    protected function getVideoIDFromSiteID($siteColumn, $siteID)
119
    {
120
        $result = null;
121
        if (\in_array($siteColumn, self::$sites, false)) {
122
            $result = Video::query()->where($siteColumn, $siteID)->first(['id']);
123
        }
124
125
        return $result !== null ? $result->id : false;
126
    }
127
128
    /**
129
     * Attempt a local lookup via the title first by exact match and then by like.
130
     * Returns a false for no match or the Video ID of the match.
131
     *
132
     * @param        $title
133
     * @param        $type
134
     * @param int    $source
135
     *
136
     * @return false|int
137
     */
138
    public function getByTitle($title, $type, $source = 0)
139
    {
140
        // Check if we already have an entry for this show.
141
        $res = $this->getTitleExact($title, $type, $source);
142
        if (isset($res)) {
143
            return $res;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $res returns the type Illuminate\Database\Eloquent\Model which is incompatible with the documented return type false|integer.
Loading history...
144
        }
145
146
        $title2 = str_replace(' and ', ' & ', $title);
147
        if ((string) $title !== (string) $title2) {
148
            $res = $this->getTitleExact($title2, $type, $source);
149
            if (isset($res)) {
150
                return $res;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $res returns the type Illuminate\Database\Eloquent\Model which is incompatible with the documented return type false|integer.
Loading history...
151
            }
152
            $pieces = explode(' ', $title2);
153
            $title2 = '%';
154
            foreach ($pieces as $piece) {
155
                $title2 .= str_replace(["'", '!'], '', $piece).'%';
156
            }
157
            $res = $this->getTitleLoose($title2, $type, $source);
158
            if (isset($res)) {
159
                return $res;
160
            }
161
        }
162
163
        // Some words are spelled correctly 2 ways
164
        // example theatre and theater
165
        $title2 = str_replace('er', 're', $title);
166
        if ((string) $title !== (string) $title2) {
167
            $res = $this->getTitleExact($title2, $type, $source);
168
            if (isset($res['id'])) {
169
                return $res['id'];
170
            }
171
            $pieces = explode(' ', $title2);
172
            $title2 = '%';
173
            foreach ($pieces as $piece) {
174
                $title2 .= str_replace(["'", '!'], '', $piece).'%';
175
            }
176
            $res = $this->getTitleLoose($title2, $type, $source);
177
            if (isset($res)) {
178
                return $res;
179
            }
180
        } else {
181
182
            // If there was not an exact title match, look for title with missing chars
183
            // example release name :Zorro 1990, tvrage name Zorro (1990)
184
            // Only search if the title contains more than one word to prevent incorrect matches
185
            $pieces = explode(' ', $title);
186
            if (\count($pieces) > 1) {
187
                $title2 = '%';
188
                foreach ($pieces as $piece) {
189
                    $title2 .= str_replace(["'", '!'], '', $piece).'%';
190
                }
191
                $res = $this->getTitleLoose($title2, $type, $source);
192
                if (isset($res)) {
193
                    return $res;
194
                }
195
            }
196
        }
197
198
        return false;
199
    }
200
201
    /**
202
     * @param $title
203
     * @param $type
204
     * @param int $source
205
     * @return bool|\Illuminate\Database\Eloquent\Model|null|static
206
     */
207
    public function getTitleExact($title, $type, $source = 0)
208
    {
209
        $return = false;
210
        if (! empty($title)) {
211
            $sql = Video::query()->where(['title' => $title, 'type' => $type]);
212
            if ($source > 0) {
213
                $sql->where('source', $source);
214
            }
215
            $query = $sql->first();
216
            if (! empty($query)) {
217
                $return = $query->value('id');
218
            }
219
            // Try for an alias
220
            if (empty($return)) {
221
                $sql = Video::query()
222
                    ->join('videos_aliases', 'videos.id', '=', 'videos_aliases.videos_id')
223
                    ->where(['videos_aliases.title' => $title, 'videos.type' => $type]);
224
                if ($source > 0) {
225
                    $sql->where('videos.source', $source);
226
                }
227
                $query = $sql->first();
228
                if (! empty($query)) {
229
                    $return = $query->value('videos.id');
230
                }
231
            }
232
        }
233
234
        return $return;
235
    }
236
237
    /**
238
     * Supplementary function for getByTitle that queries for a like match.
239
     *
240
     * @param        $title
241
     * @param        $type
242
     * @param int    $source
243
     *
244
     * @return array|false
245
     */
246
    public function getTitleLoose($title, $type, $source = 0)
247
    {
248
        $return = false;
249
250
        if (! empty($title)) {
251
            $sql = Video::query()
252
                ->where('title', 'like', rtrim($title, '%'))
253
                ->where('type', $type);
254
            if ($source > 0) {
255
                $sql->where('source', $source);
256
            }
257
            $query = $sql->first();
258
            if (! empty($query)) {
259
                $return = $query->value('id');
260
            }
261
            // Try for an alias
262
            if (empty($return)) {
263
                $sql = Video::query()
264
                    ->join('videos_aliases', 'videos.id', '=', 'videos_aliases.videos_id')
265
                    ->where('videos_aliases.title', '=', rtrim($title, '%'))
266
                    ->where('type', $type);
267
                if ($source > 0) {
268
                    $sql->where('videos.source', $source);
269
                }
270
                $query = $sql->first();
271
                if (! empty($query)) {
272
                    $return = $query->value('videos.id');
273
                }
274
            }
275
        }
276
277
        return $return;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $return also could return the type App\Models\Video|Illumin...Database\Eloquent\Model which is incompatible with the documented return type array|false.
Loading history...
278
    }
279
280
    /**
281
     * Inserts aliases for videos.
282
     *
283
     * @param       $videoId
284
     * @param array $aliases
285
     */
286
    public function addAliases($videoId, array $aliases = []): void
287
    {
288
        if (! empty($aliases) && $videoId > 0) {
289
            foreach ($aliases as $key => $title) {
290
                // Check for tvmaze style aka
291
                if (\is_array($title) && ! empty($title['name'])) {
292
                    $title = $title['name'];
293
                }
294
                // Check if we have the AKA already
295
                $check = $this->getAliases($videoId, $title);
296
297
                if ($check === false) {
298
                    VideoAlias::insertOrIgnore(['videos_id' => $videoId, 'title' => $title, 'created_at' => now(), 'updated_at' => now()]);
299
                }
300
            }
301
        }
302
    }
303
304
    /**
305
     * Retrieves all aliases for given VideoID or VideoID for a given alias.
306
     *
307
     *
308
     * @param int $videoId
309
     * @param string $alias
310
     * @return VideoAlias[]|bool|\Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection|mixed
311
     */
312
    public function getAliases(int $videoId, string $alias = '')
313
    {
314
        $return = false;
315
        $expiresAt = now()->addMinutes(config('nntmux.cache_expiry_medium'));
316
317
        if ($videoId > 0 || $alias !== '') {
318
            $aliasCache = Cache::get(md5($videoId.$alias));
319
            if ($aliasCache !== null) {
320
                $return = $aliasCache;
321
            } else {
322
                $sql = VideoAlias::query();
323
                if ($videoId > 0) {
324
                    $sql->where('videos_id', $videoId);
325
                } elseif ($alias !== '') {
326
                    $sql->where('title', $alias);
327
                }
328
                $return = $sql->get();
329
                Cache::put(md5($videoId.$alias), $return, $expiresAt);
330
            }
331
        }
332
333
        return $return->isEmpty() ? false : $return;
334
    }
335
}
336