diff --git a/BuildData.groovy b/BuildData.groovy index 31d02b98..6ff27c19 100644 --- a/BuildData.groovy +++ b/BuildData.groovy @@ -26,7 +26,7 @@ tsv.text.eachLine{ } } -movies = movies.findAll{ it[0] <= 9999999 && it[2] >= 1960 && it[1] =~ /^[A-Z0-9]/ && it[1] =~ /[\p{Alpha}]{3}/ }.sort{ it[1] } +movies = movies.findAll{ it[0] <= 9999999 && it[2] >= 1930 && it[1] =~ /^[A-Z0-9]/ && it[1] =~ /[\p{Alpha}]{3}/ }.sort{ it[1] } gz(m_out, movies.collect{ [it[0].pad(7), it[1], it[2]].join('\t') }) println "Movie Count: " + movies.size() diff --git a/source/net/sourceforge/filebot/cli/CmdlineOperations.java b/source/net/sourceforge/filebot/cli/CmdlineOperations.java index 1539a89d..e8dc7dc1 100644 --- a/source/net/sourceforge/filebot/cli/CmdlineOperations.java +++ b/source/net/sourceforge/filebot/cli/CmdlineOperations.java @@ -313,8 +313,9 @@ public class CmdlineOperations implements CmdlineInterface { derivatesByMovieFile.put(movieFile, new ArrayList()); } for (File file : orphanedFiles) { + List orphanParent = listPath(file); for (File movieFile : movieFiles) { - if (isDerived(file, movieFile)) { + if (orphanParent.contains(movieFile.getParentFile()) && isDerived(file, movieFile)) { derivatesByMovieFile.get(movieFile).add(file); break; } @@ -382,7 +383,11 @@ public class CmdlineOperations implements CmdlineInterface { if (movie == null) { CLILogger.fine(format("Auto-detect movie from context: [%s]", file)); Collection results = detectMovie(file, null, service, locale, strict); - movie = (Movie) selectSearchResult(query, results, strict).get(0); + try { + movie = (Movie) selectSearchResult(query, results, strict).get(0); + } catch (Exception e) { + CLILogger.log(Level.WARNING, String.format("%s: [%s/%s] %s", e.getClass().getSimpleName(), guessMovieFolder(file) != null ? guessMovieFolder(file).getName() : null, file.getName(), e.getMessage())); + } if (movie != null) { Analytics.trackEvent(service.getName(), "SearchMovie", movie.toString(), 1); diff --git a/source/net/sourceforge/filebot/media/MediaDetection.java b/source/net/sourceforge/filebot/media/MediaDetection.java index ad0f1680..198a746e 100644 --- a/source/net/sourceforge/filebot/media/MediaDetection.java +++ b/source/net/sourceforge/filebot/media/MediaDetection.java @@ -15,6 +15,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.text.CollationKey; import java.text.Collator; +import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; @@ -301,19 +302,13 @@ public class MediaDetection { // search by file name or folder name List terms = new ArrayList(); - // 1. term: try to match movie pattern 'name (year)' or use filename as is - Matcher nameMatcher = compile("^(.+?)[(]((?:19|20)\\d{2})[)]").matcher(movieFile.getName()); - if (nameMatcher.find()) { - terms.add(String.format("%s (%s)", nameMatcher.group(1).trim(), nameMatcher.group(2))); - } else { - terms.add(getName(movieFile)); - } + terms.add(reduceMovieName(getName(movieFile))); // 2. term: first meaningful parent folder File movieFolder = guessMovieFolder(movieFile); if (movieFolder != null) { - terms.add(getName(movieFolder)); + terms.add(reduceMovieName(getName(movieFolder))); } List movieNameMatches = matchMovieName(terms, locale, strict); @@ -329,6 +324,11 @@ public class MediaDetection { movieNameMatches = matchMovieName(terms, locale, false); } + // assume name without spacing will mess up any lookup + if (movieNameMatches.isEmpty()) { + movieNameMatches = matchMovieFromStringWithoutSpacing(terms, new NameSimilarityMetric(), strict ? 0.9f : 0.6f); + } + // query by file / folder name if (queryLookupService != null) { options.addAll(queryMovieByFileName(terms, queryLookupService, locale)); @@ -344,6 +344,15 @@ public class MediaDetection { } + public static String reduceMovieName(String name) throws IOException { + Matcher reluctantMatcher = compile("^(.+)[\\[\\(]((?:19|20)\\d{2})[\\]\\)]").matcher(name); + if (reluctantMatcher.find()) { + return String.format("%s %s", reluctantMatcher.group(1).trim(), reluctantMatcher.group(2)); + } + return name; + } + + public static File guessMovieFolder(File movieFile) throws IOException { // first meaningful parent folder (max 2 levels deep) File f = movieFile.getParentFile(); @@ -357,24 +366,39 @@ public class MediaDetection { } - private static List matchMovieName(final List files, final Locale locale, final boolean strict) throws Exception { + private static List> movieIndex; + + + private static synchronized List> getMovieIndex() throws IOException { + if (movieIndex == null) { + Movie[] movies = releaseInfo.getMovieList(); + movieIndex = new ArrayList>(movies.length); + for (Movie movie : movies) { + movieIndex.add(new SimpleEntry(normalizePunctuation(movie.getName()).toLowerCase(), movie)); + } + } + return movieIndex; + } + + + public static List matchMovieName(final List files, final Locale locale, final boolean strict) throws Exception { // cross-reference file / folder name with movie list final HighPerformanceMatcher nameMatcher = new HighPerformanceMatcher(3); final Map matchMap = new HashMap(); - for (final Movie movie : releaseInfo.getMovieList()) { + for (Entry movie : getMovieIndex()) { for (String name : files) { - String movieIdentifier = movie.getName(); + String movieIdentifier = movie.getKey(); String commonName = nameMatcher.matchFirstCommonSequence(name, movieIdentifier); if (commonName != null && commonName.length() >= movieIdentifier.length()) { - String strictMovieIdentifier = movie.getName() + " " + movie.getYear(); + String strictMovieIdentifier = movie.getKey() + " " + movie.getValue().getYear(); String strictCommonName = nameMatcher.matchFirstCommonSequence(name, strictMovieIdentifier); if (strictCommonName != null && strictCommonName.length() >= strictMovieIdentifier.length()) { // prefer strict match - matchMap.put(movie, strictCommonName); + matchMap.put(movie.getValue(), strictCommonName); } else if (!strict) { // make sure the common identifier is not just the year - matchMap.put(movie, commonName); + matchMap.put(movie.getValue(), commonName); } } } @@ -394,6 +418,32 @@ public class MediaDetection { } + public static List matchMovieFromStringWithoutSpacing(List files, SimilarityMetric metric, float similarityThreshold) throws IOException { + Pattern spacing = Pattern.compile("[\\p{Punct}\\p{Space}]+"); + + List terms = new ArrayList(files.size()); + for (String it : files) { + String term = spacing.matcher(it).replaceAll("").toLowerCase(); + if (term.length() >= 3) { + terms.add(term); // only consider words, not just random letters + } + } + + List movies = new ArrayList(); + for (Entry it : getMovieIndex()) { + String name = spacing.matcher(it.getKey()).replaceAll("").toLowerCase(); + for (String term : terms) { + if (term.contains(name) && metric.getSimilarity(name, term) >= similarityThreshold) { + movies.add(it.getValue()); + break; + } + } + } + + return movies; + } + + private static Collection queryMovieByFileName(List files, MovieIdentificationService queryLookupService, Locale locale) throws Exception { // remove blacklisted terms Set querySet = new LinkedHashSet(); diff --git a/source/net/sourceforge/filebot/media/ReleaseInfo.java b/source/net/sourceforge/filebot/media/ReleaseInfo.java index 9c658b7a..927a2111 100644 --- a/source/net/sourceforge/filebot/media/ReleaseInfo.java +++ b/source/net/sourceforge/filebot/media/ReleaseInfo.java @@ -3,6 +3,7 @@ package net.sourceforge.filebot.media; import static java.util.Arrays.*; +import static java.util.Collections.*; import static java.util.ResourceBundle.*; import static java.util.regex.Pattern.*; import static net.sourceforge.filebot.similarity.Normalization.*; @@ -28,6 +29,7 @@ import java.util.Map; import java.util.Scanner; import java.util.Set; import java.util.TreeMap; +import java.util.WeakHashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.GZIPInputStream; @@ -93,6 +95,7 @@ public class ReleaseInfo { public List cleanRelease(Collection items, boolean strict) throws IOException { Set languages = getLanguageMap(Locale.ENGLISH, Locale.getDefault()).keySet(); + Pattern clutterBracket = getClutterBracketPattern(strict); Pattern releaseGroup = getReleaseGroupPattern(strict); Pattern languageSuffix = getLanguageSuffixPattern(languages); Pattern languageTag = getLanguageTagPattern(languages); @@ -101,8 +104,8 @@ public class ReleaseInfo { Pattern resolution = getResolutionPattern(); Pattern queryBlacklist = getBlacklistPattern(); - Pattern[] blacklist = new Pattern[] { releaseGroup, languageSuffix, languageTag, videoSource, videoFormat, resolution, queryBlacklist }; - Pattern[] stopwords = new Pattern[] { getReleaseGroupPattern(true), languageSuffix, languageTag, videoSource, videoFormat, resolution }; + Pattern[] stopwords = new Pattern[] { getReleaseGroupPattern(true), languageTag, videoSource, videoFormat, resolution, languageSuffix }; + Pattern[] blacklist = new Pattern[] { clutterBracket, releaseGroup, languageTag, videoSource, videoFormat, resolution, languageSuffix, queryBlacklist }; List output = new ArrayList(items.size()); for (String it : items) { @@ -132,11 +135,9 @@ public class ReleaseInfo { for (Pattern it : stopwords) { Matcher matcher = it.matcher(item); if (matcher.find()) { - return item.substring(0, matcher.start()); // use substring before the matched stopword + item = item.substring(0, matcher.start()); // use substring before the matched stopword } } - - // no stopword found, keep original string return item; } @@ -149,7 +150,7 @@ public class ReleaseInfo { public Pattern getLanguageSuffixPattern(Collection languages) { // .en.srt - return compile("(?<=\\p{Punct}|\\s)(" + join(quoteAll(languages), "|") + ")(?=$)", CASE_INSENSITIVE | UNICODE_CASE | CANON_EQ); + return compile("(?<=[\\p{Punct}\\p{Space}])(" + join(quoteAll(languages), "|") + ")(?=[._ ]*$)", CASE_INSENSITIVE | UNICODE_CASE | CANON_EQ); } @@ -173,6 +174,13 @@ public class ReleaseInfo { } + public Pattern getClutterBracketPattern(boolean strict) { + // match patterns like [Action, Drama] or {ENG-XViD-MP3-DVDRiP} etc + String contentFilter = strict ? "[\\p{Space}\\p{Punct}&&[^\\[\\]]]" : "\\p{Alpha}"; + return compile("(?:\\[([^\\[\\]]+?" + contentFilter + "[^\\[\\]]+?)\\])|(?:\\{([^\\{\\}]+?" + contentFilter + "[^\\{\\}]+?)\\})|(?:\\(([^\\(\\)]+?" + contentFilter + "[^\\(\\)]+?)\\))"); + } + + public synchronized Pattern getReleaseGroupPattern(boolean strict) throws IOException { // pattern matching any release group name enclosed in separators return compile("(?, Map> languageMapCache = synchronizedMap(new WeakHashMap, Map>(2)); + + private Map getLanguageMap(Locale... supportedDisplayLocale) { + // try cache + Set displayLocales = new HashSet(asList(supportedDisplayLocale)); + Map languageMap = languageMapCache.get(displayLocales); + if (languageMap != null) { + return languageMap; + } + // use maximum strength collator by default Collator collator = Collator.getInstance(Locale.ROOT); collator.setDecomposition(Collator.FULL_DECOMPOSITION); @@ -322,9 +340,7 @@ public class ReleaseInfo { @SuppressWarnings("unchecked") Comparator order = (Comparator) collator; - - Map languageMap = new TreeMap(order); - Set displayLocales = new HashSet(asList(supportedDisplayLocale)); + languageMap = new TreeMap(order); for (String code : Locale.getISOLanguages()) { Locale locale = new Locale(code); @@ -341,7 +357,11 @@ public class ReleaseInfo { // remove illegal tokens languageMap.remove(""); - return languageMap; + languageMap.remove("II"); + languageMap.remove("III"); + + Map result = unmodifiableMap(languageMap); + languageMapCache.put(displayLocales, result); + return result; } - } diff --git a/source/net/sourceforge/filebot/media/ReleaseInfo.properties b/source/net/sourceforge/filebot/media/ReleaseInfo.properties index aab682b6..0aaf4838 100644 --- a/source/net/sourceforge/filebot/media/ReleaseInfo.properties +++ b/source/net/sourceforge/filebot/media/ReleaseInfo.properties @@ -1,5 +1,5 @@ # source names mostly copied from [http://en.wikipedia.org/wiki/Pirated_movie_release_types] -pattern.video.source: CAMRip|CAM|PDVD|TS|TELESYNC|PDVD|PPV|PPVRip|Screener|SCR|SCREENER|DVDSCR|DVDSCREENER|BDSCR|R5|R5LINE|DVD|DVDRip|DVDR|TVRip|DSR|PDTV|HDTV|DVB|DVBRip|DTHRip|VODRip|VODR|BDRip|BRRip|BluRay|BDR|BR-Scr|BR-Screener|HDDVD|HDRip|WorkPrint|VHS|VCD|TELECINE|WEB-DL|Webrip +pattern.video.source: CAMRip|CAM|PDVD|TS|TELESYNC|PDVD|PPV|PPVRip|Screener|SCR|SCREENER|DVDSCR|DVDSCREENER|BDSCR|R4|R5|R5LINE|R5.LINE|DVD|DVDRip|DVDR|TVRip|DSR|PDTV|HDTV|DVB|DVBRip|DTHRip|VODRip|VODR|BDRip|BRRip|BluRay|BDR|BR-Scr|BR-Screener|HDDVD|HDRip|WorkPrint|VHS|VCD|TELECINE|WEB-DL|WEBRip # additional release info patterns pattern.video.format: DivX|Xvid|AVC|x264|h264|3ivx|mpeg|mpeg4|mp3|aac|ac3|2ch|6ch|WS|HR|720p|1080p|NTSC diff --git a/source/net/sourceforge/filebot/ui/rename/MovieHashMatcher.java b/source/net/sourceforge/filebot/ui/rename/MovieHashMatcher.java index 305b155a..bc2f1fc9 100644 --- a/source/net/sourceforge/filebot/ui/rename/MovieHashMatcher.java +++ b/source/net/sourceforge/filebot/ui/rename/MovieHashMatcher.java @@ -236,10 +236,12 @@ class MovieHashMatcher implements AutoCompleteMatcher { String input = null; synchronized (inputMemory) { - input = inputMemory.get(suggestion); - if (input == null || suggestion == null || suggestion.isEmpty()) { - input = showInputDialog("Enter movie name:", suggestion, String.format("%s/%s", movieFile.getParentFile().getName(), movieFile.getName()), parent); - inputMemory.put(suggestion, input); + synchronized (this) { + input = inputMemory.get(suggestion); + if (input == null || suggestion == null || suggestion.isEmpty()) { + input = showInputDialog("Enter movie name:", suggestion, String.format("%s/%s", movieFile.getParentFile().getName(), movieFile.getName()), parent); + inputMemory.put(suggestion, input); + } } } @@ -320,8 +322,8 @@ class MovieHashMatcher implements AutoCompleteMatcher { }); // allow only one select dialog at a time - synchronized (this) { - synchronized (selectionMemory) { + synchronized (selectionMemory) { + synchronized (this) { if (selectionMemory.containsKey(fileQuery)) { return selectionMemory.get(fileQuery); } diff --git a/source/net/sourceforge/filebot/web/OpenSubtitlesXmlRpc.java b/source/net/sourceforge/filebot/web/OpenSubtitlesXmlRpc.java index 4c3811bc..03eb09ce 100644 --- a/source/net/sourceforge/filebot/web/OpenSubtitlesXmlRpc.java +++ b/source/net/sourceforge/filebot/web/OpenSubtitlesXmlRpc.java @@ -146,7 +146,7 @@ public class OpenSubtitlesXmlRpc { movies.add(new Movie(name, year, Integer.parseInt(imdbid))); } catch (Exception e) { - Logger.getLogger(OpenSubtitlesXmlRpc.class.getName()).log(Level.INFO, String.format("Ignore movie %s: %s", movie, e.getMessage())); + Logger.getLogger(OpenSubtitlesXmlRpc.class.getName()).log(Level.INFO, String.format("Ignore movie [%s]: %s", movie, e.getMessage())); } } diff --git a/source/net/sourceforge/filebot/web/TMDbClient.java b/source/net/sourceforge/filebot/web/TMDbClient.java index 1d6c599c..21dfc07d 100644 --- a/source/net/sourceforge/filebot/web/TMDbClient.java +++ b/source/net/sourceforge/filebot/web/TMDbClient.java @@ -41,8 +41,8 @@ public class TMDbClient implements MovieIdentificationService { private static final String host = "api.themoviedb.org"; private static final String version = "2.1"; - private static final FloodLimit SEARCH_LIMIT = new FloodLimit(10, 10, TimeUnit.SECONDS); - private static final FloodLimit REQUEST_LIMIT = new FloodLimit(20, 10, TimeUnit.SECONDS); + private static final FloodLimit SEARCH_LIMIT = new FloodLimit(10, 12, TimeUnit.SECONDS); + private static final FloodLimit REQUEST_LIMIT = new FloodLimit(30, 12, TimeUnit.SECONDS); private final String apikey; @@ -114,18 +114,27 @@ public class TMDbClient implements MovieIdentificationService { List result = new ArrayList(); for (Node node : selectNodes("//movie", dom)) { + String name = getTextContent("name", node); try { - String name = getTextContent("name", node); - // release date format will be YYYY-MM-DD, but we only care about the year - int year = new Scanner(getTextContent("released", node)).useDelimiter("\\D+").nextInt(); + int year = -1; + try { + year = new Scanner(getTextContent("released", node)).useDelimiter("\\D+").nextInt(); + } catch (RuntimeException e) { + throw new IllegalArgumentException("Missing data: year"); + } // imdb id will be tt1234567, but we only care about the number - int imdbid = new Scanner(getTextContent("imdb_id", node)).useDelimiter("\\D+").nextInt(); + int imdbid = -1; + try { + imdbid = new Scanner(getTextContent("imdb_id", node)).useDelimiter("\\D+").nextInt(); + } catch (RuntimeException e) { + throw new IllegalArgumentException("Missing data: imdbid"); + } result.add(new Movie(name, year, imdbid)); - } catch (RuntimeException e) { - // release date or imdb id are undefined + } catch (Exception e) { + Logger.getLogger(TMDbClient.class.getName()).log(Level.INFO, String.format("Ignore movie [%s]: %s", name, e.getMessage())); } } diff --git a/website/data/query-blacklist.txt b/website/data/query-blacklist.txt index 8f80d9ac..1e19b0ce 100644 --- a/website/data/query-blacklist.txt +++ b/website/data/query-blacklist.txt @@ -1,7 +1,18 @@ +(?-i:CLASSiC) +(?-i:DOCU) +(?-i:ENGLISH) +(?-i:FIXED) +(?-i:FRENCH) +(?-i:GERMAN) +(?-i:iNT) +(?-i:LIMITED|LiMiTED) +(?-i:SPANISH) +(?-i:SWEDISH|SWEDiSH) .+sample$ 1-3-3-8.com 5[.,]1 @KIDZ +[1-3]CD [1-3]CDRip [1-9].?of.?[1-9] ^(TV.)?(Show|Serie)[s]? @@ -13,6 +24,7 @@ ^Film[s]? ^HVDVD_TS$ ^Info +^l[^\p{Alnum}] ^Movie[s]? ^New$ ^SAMPLE @@ -28,24 +40,28 @@ By.Cool.Release CD[0]?[1-3] CN CVCD +DC Demonoid +Director's.Cut Directors.Cut +Dual.Audio +dubbed +DVDXvID DVSKY ENG -ENGLISH EXTENDED Extended.Version ExtraScene ExtraTorrent +Final.Cut Fra FRE -FRENCH GER -GERMAN Hard.Subbed HDRip Hindi HQ +iNTERNAL iPod ISO iTA @@ -53,9 +69,11 @@ iTALIA jigaxx KIDZCORNER KOR +KORSUB +LMAO Los.Sustitutos mkvonly -Movie[s]? +MultiSub MVGroup.org NL NL.Subs @@ -65,9 +83,12 @@ PROPER PSP READNFO REAL.PROPER +REMASTERED REPACK +ReRip RESYNC RETAIL +RiffTrax Sample sample[s]?$ Screenshot @@ -77,7 +98,7 @@ ShareZONE ShortKut Snapshots SPA -SPANISH +Special.Edition Sub SUBBED Subs @@ -87,10 +108,12 @@ swe.?sub SYNC SYNCFIX TC +theatrical.cut TPB TRUEFRENCH TS TSXVID +ultimate.edition UNCUT unrated unrated.edition diff --git a/website/data/release-groups.txt b/website/data/release-groups.txt index be852b42..04f58174 100644 --- a/website/data/release-groups.txt +++ b/website/data/release-groups.txt @@ -9,6 +9,7 @@ 2WIRE 310yuma 3Li +3LT0N 420RipZ 4HM 7SiNS @@ -18,6 +19,7 @@ aacrime aAF AaS aBD +AbSurdity aceford ADHD AE @@ -32,14 +34,19 @@ AKUPX ALANiS ALeSiO ALLiANCE +ALLZINE AMiABLE +AN0NYM0US +aNBc ANBU Ani-Kraze ANiHLS AonE ARiGOLD ARROW +ArtSubs ASAP +ATTENTATET AVCHD AVS720 AW @@ -56,6 +63,7 @@ bc10 BDClub BDiSC beAst +BeStDivX BestHD BiA BiDA @@ -69,6 +77,7 @@ BLUEYES blueZilla BluWave BMB +BORGATA bReAK BrG BRiGHT @@ -109,13 +118,13 @@ COALiTiON Cocksure COMPULSION cottage +COWiSO CPtScene CPY CRF CRIMSON CRiSC CROSSBOW -Crow CRYS CSHD CtrlHD @@ -131,15 +140,18 @@ DARM DASH DATA DAW +DCA DDC dddc DEAL decibeL +DEFACED DEFiNiTE DEFiNiTiON DEFUSED DEiTY DEPRAViTY +DEPRiVED DETAiLS DEViSE DEWSTRR @@ -163,6 +175,7 @@ DnB DNL DNR DON +DoNE DOT doubt DOWN @@ -171,6 +184,7 @@ DUPLI DUQA DutchReleaseTeam DvF +DVL EBi EbP ECHiZEN @@ -183,6 +197,7 @@ Electri4ka ELECTRiC Electrichka elizabethtga +EM0C0RE EmC EMPiREHD ENCOUNTERS @@ -190,6 +205,7 @@ EnDoR eots EPiK ESiR +ESPiSE ETHOS ETM ETRG @@ -198,8 +214,11 @@ EuchHD EUHD EuReKA EUSTASS +EwDp +EXiLE EXQUiSiTE ExtraTorrentRG +EXViD eztv FaNSuB FASM @@ -210,10 +229,14 @@ FHM FiCO FiHTV FilmHD +FiNaLe +fjall FLAiTE +Flaket fLAMEhd FLAWL3SS Flomp-Rumbel +FLS FLX FmE ForceBleue @@ -232,6 +255,7 @@ FTVDT FTW-FM FTW-HD fty +FUCT Funner FXG FxM @@ -239,8 +263,10 @@ G3N3 GAGE Gazdi GB +GECKOS GEHENNA george.c +GFW GFY GiNJi GMoRK @@ -250,6 +276,7 @@ GoLDSToNE GOTHiC GriOTS Grond +gudhak H2 h264iRMU H@M @@ -293,6 +320,7 @@ HiFi HiGHTIMES HiNT HoodBag +HORiZON HOWL HqDTS HUBRiS @@ -305,10 +333,13 @@ iaK iBEX iCANDY iGNHD +iGNiTiON IGUANA iKA +iLG iLL iMAGiNE +iMBT IMF IMMERSE imNaKeD @@ -330,6 +361,7 @@ JAVLiU JCH JENC JJH +JoLLyRoGeR K-F k2 KaKa @@ -337,7 +369,9 @@ kamera keltz KiNGS KLAXXON +KlockreN KOENiG +KonzillaRG KRaLiMaRKo KYR Kyuubi @@ -355,6 +389,7 @@ LOLCATS LoneWolf LOST LP +LTRG LTT LUSO M794 @@ -367,6 +402,7 @@ MARiNES MAXSPEED MC MCR +MEDiAMANiACS MEDiEVAL MELiTE MeTH @@ -376,16 +412,20 @@ MiND MiNT MiRAGETV MMI +MoF MOMENTUM MONK MOREHD MOTU +MOViERUSH MOViESTARS +MrLore mSD MsR MuSt mV4U mVmHD +MXMG MySiLU N-F NaRB @@ -405,8 +445,9 @@ Nile NiX NL.Subs NODLABS +NoGrp NOHD -Noir +NOiR NORARS NoSCR NOsegmenT @@ -427,12 +468,15 @@ ONYX ORC ORENJi ORPHEUS +OSiRiS OSiTV OUTDATED OZC P0W4 Pa@Ph +PADDO papi +PARTiCLE PaYxXx PeeWee PELLUCiD @@ -445,12 +489,15 @@ PiLAF PiNER PiX PixelHD +playXD POD PoRNDoCtOR PORNOHOLiCS +PosTX PoTuS PP PPQ +PRECiOUS Prime PriMeHD PRiNCE @@ -460,10 +507,11 @@ PROPHETS ProPL PRXHD PS3-TEAM -psig +PSiG PSV PSYCHD Pti +PtP PtS Pudding Pukka @@ -474,6 +522,7 @@ PxHD Q0S QCF QDP +QiX QSP QXE R&C @@ -493,14 +542,17 @@ REWARD RightSiZE RiplleyHD RiPTATORz +RiTALiX RiVER RMT RoCKRioT ROVERS RSG RTA +RUBY RuDE RUDOS +RUSTLE Ryugan S26 SAiMORNY @@ -508,10 +560,12 @@ SAiNTS SAiVERT SAMFD SANTI -saphire +SAPHiRE Sapphire +SChiZO Scratch404 Scratched +ScWb SecretMyth SECTOR7 SEMTEX @@ -526,6 +580,7 @@ SHDXXX shortbrehd SHS SHUNPO +SiC SiGHTHD SiHD SiLU @@ -536,6 +591,7 @@ SLM SLO SMoKeR Sneak +SNUGGLER SoCkS Softfeng SoW @@ -543,6 +599,7 @@ SpaceHD SPARKS SPOOKY SSF +Stealthmaster stieg Stranded streetwars @@ -556,18 +613,24 @@ Swesub SYS t00ng0d Taka +TARGET +TASTE TASTETV TB +TDF TELEFLiX TENEIGHTY TERRA terribleHD terribleSD THENiGHTMAREiNHD +TheWretched THOR THORA THUGLiNE +TiDE TiMELORDS +TiMPE TiMTY TiTANS TjHD @@ -599,16 +662,21 @@ UNVEiL USELESS UVall VaAr3 +VALiOMEDiA +VAMPS Vanillapunk VanRay VCDVaULT +VeGaN Vegapunk ViCiOsO ViKAT ViNYL +ViP3R ViSiON ViSTA ViSTAâ„¢ +ViTE VLiS VOA VoMiT @@ -618,6 +686,7 @@ VoXHD vrs w0rm w4f +WAF WANKAZ WASTE WAVEY @@ -643,6 +712,7 @@ XSHD XSTREEM XTM XTSF +XviK XXX4U YanY YellowBeast