Completed
Push — dev ( 1c59fb...0e163e )
by Darko
25s queued 13s
created

Videos::getAlternativeTitleExact()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 24
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 18
c 1
b 0
f 0
dl 0
loc 24
ccs 0
cts 10
cp 0
rs 9.6666
cc 4
nc 5
nop 3
crap 20
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
     * @param $title
130
     * @param $type
131
     * @param int $source
132
     * @return $this|array|bool|false|\Illuminate\Database\Eloquent\Model|mixed|null
133
     */
134
    public function getByTitle($title, $type, $source = 0)
135
    {
136
        // Check if we already have an entry for this show.
137
        $res = $this->getTitleExact($title, $type, $source);
138
        if ($res) {
139
            return $res;
140
        }
141
        
142
        // Check alt. title (Strip ' and :) Maybe strip more in the future.
143
        $res = $this->getAlternativeTitleExact($title, $type, $source);
144
        if ($res) {
145
            return $res;
146
        }
147
148
        $title2 = str_ireplace(' and ', ' & ', $title);
149
        if ((string) $title !== (string) $title2) {
150
            $res = $this->getTitleExact($title2, $type, $source);
151
            if ($res) {
152
                return $res;
153
            }
154
            $pieces = explode(' ', $title2);
155
            $title2 = '%';
156
            foreach ($pieces as $piece) {
157
                $title2 .= str_ireplace(["'", '!'], '', $piece).'%';
158
            }
159
            $res = $this->getTitleLoose($title2, $type, $source);
160
            if ($res) {
0 ignored issues
show
introduced by
The condition $res is always false.
Loading history...
161
                return $res;
162
            }
163
        }
164
165
        // Some words are spelled correctly 2 ways
166
        // example theatre and theater
167
        $title2 = str_ireplace('er', 're', $title);
168
        if ((string) $title !== (string) $title2) {
169
            $res = $this->getTitleExact($title2, $type, $source);
170
            if ($res['id']) {
171
                return $res['id'];
172
            }
173
            $pieces = explode(' ', $title2);
174
            $title2 = '%';
175
            foreach ($pieces as $piece) {
176
                $title2 .= str_ireplace(["'", '!'], '', $piece).'%';
177
            }
178
            $res = $this->getTitleLoose($title2, $type, $source);
179
            if ($res) {
0 ignored issues
show
introduced by
The condition $res is always false.
Loading history...
180
                return $res;
181
            }
182
        } else {
183
184
            // If there was not an exact title match, look for title with missing chars
185
            // example release name :Zorro 1990, tvrage name Zorro (1990)
186
            // Only search if the title contains more than one word to prevent incorrect matches
187
            $pieces = explode(' ', $title);
188
            if (\count($pieces) > 1) {
189
                $title2 = '%';
190
                foreach ($pieces as $piece) {
191
                    $title2 .= str_ireplace(["'", '!'], '', $piece).'%';
192
                }
193
                $res = $this->getTitleLoose($title2, $type, $source);
194
                if ($res) {
0 ignored issues
show
introduced by
The condition $res is always false.
Loading history...
195
                    return $res;
196
                }
197
            }
198
        }
199
200
        return false;
201
    }
202
203
    /**
204
     * @param $title
205
     * @param $type
206
     * @param int $source
207
     * @return bool|\Illuminate\Database\Eloquent\Model|null|static
208
     */
209
    public function getTitleExact($title, $type, $source = 0)
210
    {
211
        $return = false;
212
        if (! empty($title)) {
213
            $sql = Video::query()->where(['title' => $title, 'type' => $type]);
214
            if ($source > 0) {
215
                $sql->where('source', $source);
216
            }
217
            $query = $sql->first();
218
            if (! empty($query)) {
219
                $return = $query->id;
220
            }
221
            // Try for an alias
222
            if (empty($return)) {
223
                $sql = Video::query()
224
                    ->join('videos_aliases', 'videos.id', '=', 'videos_aliases.videos_id')
225
                    ->where(['videos_aliases.title' => $title, 'videos.type' => $type]);
226
                if ($source > 0) {
227
                    $sql->where('videos.source', $source);
228
                }
229
                $query = $sql->first();
230
                if (! empty($query)) {
231
                    $return = $query->id;
232
                }
233
            }
234
        }
235
236
        return $return;
237
    }
238
239
    /**
240
     * Supplementary function for getByTitle that queries for a like match.
241
     *
242
     * @param        $title
243
     * @param        $type
244
     * @param int    $source
245
     *
246
     * @return array|false
247
     */
248
    public function getTitleLoose($title, $type, $source = 0)
249
    {
250
        $return = false;
251
252
        if (! empty($title)) {
253
            $sql = Video::query()
254
                ->where('title', 'like', rtrim($title, '%'))
255
                ->where('type', $type);
256
            if ($source > 0) {
257
                $sql->where('source', $source);
258
            }
259
            $query = $sql->first();
260
            if (! empty($query)) {
261
                $return = $query->id;
262
            }
263
            // Try for an alias
264
            if (empty($return)) {
265
                $sql = Video::query()
266
                    ->join('videos_aliases', 'videos.id', '=', 'videos_aliases.videos_id')
267
                    ->where('videos_aliases.title', '=', rtrim($title, '%'))
268
                    ->where('type', $type);
269
                if ($source > 0) {
270
                    $sql->where('videos.source', $source);
271
                }
272
                $query = $sql->first();
273
                if (! empty($query)) {
274
                    $return = $query->id;
275
                }
276
            }
277
        }
278
279
        return $return;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $return also could return the type integer which is incompatible with the documented return type array|false.
Loading history...
280
    }
281
    
282
    /**
283
     * Supplementary function for getByTitle that replaces special chars to find an exact match.
284
     * Add more ->whereRaw() methods if needed. Might slow TV PP down though.
285
     *
286
     * @param $title
287
     * @param $type
288
     * @param int $source
289
     * @return bool|\Illuminate\Database\Eloquent\Model|null|static
290
     */
291
    public function getAlternativeTitleExact($title, $type, $source = 0)
292
    {
293
        $return = false;
294
        if (! empty($title)) {
295
            if ($source > 0) {
296
                $query = DB::table('videos')
0 ignored issues
show
Bug introduced by
The type Blacklight\processing\DB was not found. Did you mean DB? If so, make sure to prefix the type with \.
Loading history...
297
                ->whereRaw("REPLACE(title,'\'','') = ?", $title)
298
                ->orWhereRaw("REPLACE(title,':','') = ?", $title)
299
                ->where("type", "=", $type)
300
                ->where("source", "=", $source)
301
                ->first();
302
            } else {
303
                $query = DB::table('videos')
304
                ->whereRaw("REPLACE(title,'\'','') = ?", $title)
305
                ->orWhereRaw("REPLACE(title,':','') = ?", $title)
306
                ->where("type", "=", $type)
307
                ->first();
308
            }
309
            if (! empty($query)) {
310
                $return = $query->id;
311
            }
312
        }
313
314
        return $return;
315
    }
316
317
    /**
318
     * Inserts aliases for videos.
319
     *
320
     * @param       $videoId
321
     * @param array $aliases
322
     */
323
    public function addAliases($videoId, array $aliases = []): void
324
    {
325
        if (! empty($aliases) && $videoId > 0) {
326
            foreach ($aliases as $key => $title) {
327
                // Check for tvmaze style aka
328
                if (\is_array($title) && ! empty($title['name'])) {
329
                    $title = $title['name'];
330
                }
331
                // Check if we have the AKA already
332
                $check = $this->getAliases($videoId, $title);
333
334
                if ($check === false) {
335
                    VideoAlias::insertOrIgnore(['videos_id' => $videoId, 'title' => $title, 'created_at' => now(), 'updated_at' => now()]);
336
                }
337
            }
338
        }
339
    }
340
341
    /**
342
     * Retrieves all aliases for given VideoID or VideoID for a given alias.
343
     *
344
     *
345
     * @param int $videoId
346
     * @param string $alias
347
     * @return VideoAlias[]|bool|\Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection|mixed
348
     */
349
    public function getAliases(int $videoId, string $alias = '')
350
    {
351
        $return = false;
352
        $expiresAt = now()->addMinutes(config('nntmux.cache_expiry_medium'));
353
354
        if ($videoId > 0 || $alias !== '') {
355
            $aliasCache = Cache::get(md5($videoId.$alias));
356
            if ($aliasCache !== null) {
357
                $return = $aliasCache;
358
            } else {
359
                $sql = VideoAlias::query();
360
                if ($videoId > 0) {
361
                    $sql->where('videos_id', $videoId);
362
                } elseif ($alias !== '') {
363
                    $sql->where('title', $alias);
364
                }
365
                $return = $sql->get();
366
                Cache::put(md5($videoId.$alias), $return, $expiresAt);
367
            }
368
        }
369
370
        return $return->isEmpty() ? false : $return;
371
    }
372
}
373