Passed
Push — master ( 5d5926...04c44e )
by Darko
16:19
created

Videos::getAliases()   B

Complexity

Conditions 7
Paths 10

Size

Total Lines 22
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 15
c 2
b 0
f 0
dl 0
loc 22
rs 8.8333
cc 7
nc 10
nop 2
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
 *
19
 * @author    niel
20
 * @copyright 2015 nZEDb
21
 */
22
23
namespace Blacklight\processing;
24
25
use App\Models\TvInfo;
26
use App\Models\Video;
27
use App\Models\VideoAlias;
28
use Illuminate\Support\Facades\Cache;
29
30
/**
31
 * Parent class for TV/Film and any similar classes to inherit from.
32
 */
33
abstract class Videos
34
{
35
    // Video Type Identifiers
36
    protected const TYPE_TV = 0; // Type of video is a TV Programme/Show
37
38
    protected const TYPE_FILM = 1; // Type of video is a Film/Movie
39
40
    protected const TYPE_ANIME = 2; // Type of video is a Anime
41
42
    public bool $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 array $titleCache;
53
54
    public function __construct()
55
    {
56
        $this->echooutput = config('nntmux.echocli');
57
        $this->titleCache = [];
58
    }
59
60
    /**
61
     * Main processing director function for scrapers
62
     * Calls work query function and initiates processing.
63
     */
64
    abstract protected function processSite(int $groupID, string $guidChar, int $process, bool $local = false): void;
65
66
    /**
67
     * Get video info from a Video ID and column.
68
     *
69
     * @return array|false False if invalid site, or ID not found; Site id value otherwise.
70
     */
71
    protected function getSiteIDFromVideoID(string $siteColumn, int $videoID): bool|array
72
    {
73
        if (\in_array($siteColumn, self::$sites, false)) {
74
            $result = Video::query()->where('id', $videoID)->first([$siteColumn]);
75
76
            return $result !== null ? $result[$siteColumn] : false;
77
        }
78
79
        return false;
80
    }
81
82
    /**
83
     * Get TV show local timezone from a Video ID.
84
     *
85
     * @return string Empty string if no query return or tz style timezone
86
     */
87
    protected function getLocalZoneFromVideoID(int $videoID): string
88
    {
89
        $result = TvInfo::query()->where('videos_id', $videoID)->first(['localzone']);
90
91
        return $result !== null ? $result['localzone'] : '';
92
    }
93
94
    /**
95
     * Get video info from a Site ID and column.
96
     */
97
    protected function getVideoIDFromSiteID(string $siteColumn, int $siteID): bool|int
98
    {
99
        $result = false;
100
        if (\in_array($siteColumn, self::$sites, false)) {
101
            $result = Video::query()->where($siteColumn, $siteID)->first();
102
        }
103
        if (! empty($result)) {
104
            $query = $result->toArray();
105
106
            return $query['id'];
107
        }
108
109
        return false;
110
    }
111
112
    public function getByTitle(string $title, int $type, int $source = 0)
113
    {
114
        // Check if we already have an entry for this show.
115
        $res = $this->getTitleExact($title, $type, $source);
116
        if ($res !== 0) {
117
            return $res;
118
        }
119
120
        // Check alt. title (Strip ' and :) Maybe strip more in the future.
121
        $res = $this->getAlternativeTitleExact($title, $type, $source);
122
        if ($res !== 0) {
123
            return $res;
124
        }
125
126
        $title2 = str_ireplace(' and ', ' & ', $title);
127
        if ((string) $title !== (string) $title2) {
128
            $res = $this->getTitleExact($title2, $type, $source);
0 ignored issues
show
Bug introduced by
It seems like $title2 can also be of type array; however, parameter $title of Blacklight\processing\Videos::getTitleExact() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

128
            $res = $this->getTitleExact(/** @scrutinizer ignore-type */ $title2, $type, $source);
Loading history...
129
            if ($res !== 0) {
130
                return $res;
131
            }
132
            $pieces = explode(' ', $title2);
0 ignored issues
show
Bug introduced by
It seems like $title2 can also be of type array; however, parameter $string of explode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

132
            $pieces = explode(' ', /** @scrutinizer ignore-type */ $title2);
Loading history...
133
            $title2 = '%';
134
            foreach ($pieces as $piece) {
135
                $title2 .= str_ireplace(["'", '!'], '', $piece).'%';
0 ignored issues
show
Bug introduced by
Are you sure str_ireplace(array(''', '!'), '', $piece) of type array|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

135
                $title2 .= /** @scrutinizer ignore-type */ str_ireplace(["'", '!'], '', $piece).'%';
Loading history...
136
            }
137
            $res = $this->getTitleLoose($title2, $type, $source);
138
            if ($res !== 0) {
139
                return $res;
140
            }
141
        }
142
143
        // Some words are spelled correctly 2 ways
144
        // example theatre and theater
145
        $title2 = str_ireplace('er', 're', $title);
146
        if ((string) $title !== (string) $title2) {
147
            $res = $this->getTitleExact($title2, $type, $source);
148
            if ($res !== 0) {
149
                return $res;
150
            }
151
            $pieces = explode(' ', $title2);
152
            $title2 = '%';
153
            foreach ($pieces as $piece) {
154
                $title2 .= str_ireplace(["'", '!'], '', $piece).'%';
155
            }
156
            $res = $this->getTitleLoose($title2, $type, $source);
157
            if ($res !== 0) {
158
                return $res;
159
            }
160
        } else {
161
            // If there was not an exact title match, look for title with missing chars
162
            // example release name :Zorro 1990, tvrage name Zorro (1990)
163
            // Only search if the title contains more than one word to prevent incorrect matches
164
            $pieces = explode(' ', $title);
165
            if (\count($pieces) > 1) {
166
                $title2 = '%';
167
                foreach ($pieces as $piece) {
168
                    $title2 .= str_ireplace(["'", '!'], '', $piece).'%';
169
                }
170
                $res = $this->getTitleLoose($title2, $type, $source);
171
                if ($res !== 0) {
172
                    return $res;
173
                }
174
            }
175
        }
176
177
        return 0;
178
    }
179
180
    public function getTitleExact(string $title, int $type, int $source = 0): int
181
    {
182
        $return = 0;
183
        if (! empty($title)) {
184
            $sql = Video::query()->where(['title' => $title, 'type' => $type]);
185
            if ($source > 0) {
186
                $sql->where('source', $source);
187
            }
188
            $query = $sql->first();
189
            if (! empty($query)) {
190
                $result = $query->toArray();
191
                $return = $result['id'];
192
            }
193
            // Try for an alias
194
            if (empty($return)) {
195
                $sql = Video::query()
196
                    ->join('videos_aliases', 'videos.id', '=', 'videos_aliases.videos_id')
197
                    ->where(['videos_aliases.title' => $title, 'videos.type' => $type]);
198
                if ($source > 0) {
199
                    $sql->where('videos.source', $source);
200
                }
201
                $query = $sql->first();
202
                if (! empty($query)) {
203
                    $result = $query->toArray();
204
                    $return = $result['id'];
205
                }
206
            }
207
        }
208
209
        return $return;
210
    }
211
212
    /**
213
     * @return int|mixed
214
     */
215
    public function getTitleLoose($title, $type, int $source = 0): mixed
216
    {
217
        $return = 0;
218
219
        if (! empty($title)) {
220
            $sql = Video::query()
221
                ->where('title', 'like', rtrim($title, '%'))
222
                ->where('type', $type);
223
            if ($source > 0) {
224
                $sql->where('source', $source);
225
            }
226
            $query = $sql->first();
227
            if (! empty($query)) {
228
                $result = $query->toArray();
229
                $return = $result['id'];
230
            }
231
            // Try for an alias
232
            if (empty($return)) {
233
                $sql = Video::query()
234
                    ->join('videos_aliases', 'videos.id', '=', 'videos_aliases.videos_id')
235
                    ->where('videos_aliases.title', '=', rtrim($title, '%'))
236
                    ->where('type', $type);
237
                if ($source > 0) {
238
                    $sql->where('videos.source', $source);
239
                }
240
                $query = $sql->first();
241
                if (! empty($query)) {
242
                    $result = $query->toArray();
243
                    $return = $result['id'];
244
                }
245
            }
246
        }
247
248
        return $return;
249
    }
250
251
    /**
252
     * @return int|mixed
253
     */
254
    public function getAlternativeTitleExact(string $title, int $type, int $source = 0): mixed
255
    {
256
        $return = 0;
257
        if (! empty($title)) {
258
            if ($source > 0) {
259
                $query = Video::query()
260
                    ->whereRaw("REPLACE(title,'\'','') = ?", $title)
261
                    ->orWhereRaw("REPLACE(title,':','') = ?", $title)
262
                    ->where('type', '=', $type)
263
                    ->where('source', '=', $source)
264
                    ->first();
265
            } else {
266
                $query = Video::query()
267
                    ->whereRaw("REPLACE(title,'\'','') = ?", $title)
268
                    ->orWhereRaw("REPLACE(title,':','') = ?", $title)
269
                    ->where('type', '=', $type)
270
                    ->first();
271
            }
272
            if (! empty($query)) {
273
                $result = $query->toArray();
274
275
                return $result['id'];
276
            }
277
        }
278
279
        return $return;
280
    }
281
282
    /**
283
     * Inserts aliases for videos.
284
     */
285
    public function addAliases($videoId, array $aliases = []): void
286
    {
287
        if (! empty($aliases) && $videoId > 0) {
288
            foreach ($aliases as $key => $title) {
289
                // Check for tvmaze style aka
290
                if (\is_array($title) && ! empty($title['name'])) {
291
                    $title = $title['name'];
292
                }
293
                // Check if we have the AKA already
294
                $check = $this->getAliases($videoId, $title);
295
296
                if ($check === false) {
297
                    VideoAlias::insertOrIgnore(['videos_id' => $videoId, 'title' => $title, 'created_at' => now(), 'updated_at' => now()]);
298
                }
299
            }
300
        }
301
    }
302
303
    /**
304
     * Retrieves all aliases for given VideoID or VideoID for a given alias.
305
     *
306
     *
307
     * @return VideoAlias[]|bool|\Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection|mixed
308
     */
309
    public function getAliases(int $videoId, string $alias = ''): mixed
310
    {
311
        $return = false;
312
        $expiresAt = now()->addMinutes(config('nntmux.cache_expiry_medium'));
313
314
        if ($videoId > 0 || $alias !== '') {
315
            $aliasCache = Cache::get(md5($videoId.$alias));
316
            if ($aliasCache !== null) {
317
                $return = $aliasCache;
318
            } else {
319
                $sql = VideoAlias::query();
320
                if ($videoId > 0) {
321
                    $sql->where('videos_id', $videoId);
322
                } elseif ($alias !== '') {
323
                    $sql->where('title', $alias);
324
                }
325
                $return = $sql->get();
326
                Cache::put(md5($videoId.$alias), $return, $expiresAt);
327
            }
328
        }
329
330
        return $return->isEmpty() ? false : $return;
331
    }
332
}
333