Add GalleryDir
This commit is contained in:
1 parent
48e379d356
commit
0eff20b45a
4 files changed
+200
-159
No files matched your search
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright 2015 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer.gallery;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.hippo.ehviewer.client.data.GalleryBase;
|
||||
import com.hippo.ehviewer.util.DBUtils;
|
||||
import com.hippo.ehviewer.util.EhUtils;
|
||||
import com.hippo.ehviewer.util.Settings;
|
||||
import com.hippo.unifile.UniFile;
|
||||
import com.hippo.yorozuya.FileUtils;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||
|
||||
public class GalleryDir {
|
||||
|
||||
private static final String[] POSSIBLE_IMAGE_EXTENSIONS = new String[] {
|
||||
"jpg", "jpeg", "png", "gif"
|
||||
};
|
||||
|
||||
private String mDirname;
|
||||
|
||||
private UniFile mUniFile;
|
||||
|
||||
private AtomicReferenceArray<String> mFilenames;
|
||||
|
||||
public static String generateImageFilename(int index, String extension) {
|
||||
return String.format("%08d.%s", index + 1, extension);
|
||||
}
|
||||
|
||||
private static String getDirname(GalleryBase galleryBase) {
|
||||
String dirname = DBUtils.getDirname(galleryBase.gid);
|
||||
if (dirname == null) {
|
||||
dirname = FileUtils.ensureFilename(galleryBase.gid + "-" + EhUtils.getSuitableTitle(galleryBase));
|
||||
DBUtils.addDirname(galleryBase, dirname);
|
||||
}
|
||||
return dirname;
|
||||
}
|
||||
|
||||
public GalleryDir(GalleryBase galleryBase) {
|
||||
mDirname = getDirname(galleryBase);
|
||||
}
|
||||
|
||||
public void ensureUniFile() {
|
||||
if (mUniFile == null) {
|
||||
mUniFile = Settings.getImageDownloadLocation().createDirectory(mDirname);
|
||||
}
|
||||
}
|
||||
|
||||
public void ensureFilenames(int pages) {
|
||||
if (mFilenames == null) {
|
||||
mFilenames = new AtomicReferenceArray<>(pages);
|
||||
}
|
||||
}
|
||||
|
||||
public UniFile getDir() {
|
||||
return mUniFile;
|
||||
}
|
||||
|
||||
private String guessImageFilename(int index) {
|
||||
if (mUniFile == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (String extension : POSSIBLE_IMAGE_EXTENSIONS) {
|
||||
String filename = generateImageFilename(index, extension);
|
||||
if (mUniFile.findFile(filename) != null) {
|
||||
return filename;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public @Nullable String getImageFilename(int index) {
|
||||
if (mFilenames == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String filename = mFilenames.get(index);
|
||||
if (filename == null) {
|
||||
filename = guessImageFilename(index);
|
||||
if (filename != null) {
|
||||
// Put filename into array
|
||||
mFilenames.lazySet(index, filename);
|
||||
}
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
public @Nullable UniFile getImageFile(int index) {
|
||||
if (mUniFile == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String filename = getImageFilename(index);
|
||||
if (filename != null) {
|
||||
return mUniFile.createFile(filename);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public @Nullable UniFile findImageFile(int index) {
|
||||
if (mUniFile == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String filename = getImageFilename(index);
|
||||
if (filename != null) {
|
||||
return mUniFile.findFile(filename);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void putImageFilename(String filename, int index) {
|
||||
if (mFilenames != null) {
|
||||
mFilenames.lazySet(index, filename);
|
||||
}
|
||||
}
|
||||
|
||||
public @Nullable UniFile createUniFile(String filename) {
|
||||
if (mUniFile == null) {
|
||||
return null;
|
||||
} else {
|
||||
return mUniFile.createFile(filename);
|
||||
}
|
||||
}
|
||||
|
||||
public @Nullable UniFile findUniFile(String filename) {
|
||||
if (mUniFile == null) {
|
||||
return null;
|
||||
} else {
|
||||
return mUniFile.findFile(filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,10 +22,6 @@ import android.os.Process;
|
||||
import com.hippo.ehviewer.client.data.GalleryBase;
|
||||
import com.hippo.ehviewer.network.EhHttpClient;
|
||||
import com.hippo.ehviewer.util.DBUtils;
|
||||
import com.hippo.ehviewer.util.EhUtils;
|
||||
import com.hippo.ehviewer.util.Settings;
|
||||
import com.hippo.unifile.UniFile;
|
||||
import com.hippo.yorozuya.FileUtils;
|
||||
import com.hippo.yorozuya.OSUtils;
|
||||
import com.hippo.yorozuya.PriorityThreadFactory;
|
||||
import com.hippo.yorozuya.SafeSparseArray;
|
||||
@@ -48,8 +44,6 @@ public class GallerySpider implements GalleryProvider, SpiderQueen.SpiderListene
|
||||
|
||||
private ImageHandler.Mode mMode;
|
||||
private GalleryBase mGalleryBase;
|
||||
private UniFile mDownloadDirParent;
|
||||
private String mDownloadDirname;
|
||||
private ThreadFactory mThreadFactory = new PriorityThreadFactory("SpiderQueen",
|
||||
Process.THREAD_PRIORITY_BACKGROUND);
|
||||
private SpiderQueen mSpiderQueen;
|
||||
@@ -96,25 +90,9 @@ public class GallerySpider implements GalleryProvider, SpiderQueen.SpiderListene
|
||||
}
|
||||
}
|
||||
|
||||
private static String downloadDirname(GalleryBase galleryBase) {
|
||||
return FileUtils.ensureFilename(galleryBase.gid + "-" + EhUtils.getSuitableTitle(galleryBase));
|
||||
}
|
||||
|
||||
private GallerySpider(GalleryBase galleryBase, ImageHandler.Mode mode) throws IOException {
|
||||
mGalleryBase = galleryBase;
|
||||
mMode = mode;
|
||||
|
||||
// TODO let imagehandler handle download dir
|
||||
mDownloadDirname = DBUtils.getDirname(galleryBase.gid);
|
||||
if (mDownloadDirname == null) {
|
||||
mDownloadDirname = downloadDirname(galleryBase);
|
||||
DBUtils.addDirname(galleryBase, mDownloadDirname);
|
||||
}
|
||||
|
||||
mDownloadDirParent = Settings.getImageDownloadLocation();
|
||||
if (mDownloadDirParent == null) {
|
||||
throw new IOException("Can't get download dir");
|
||||
}
|
||||
}
|
||||
|
||||
public void setMode(ImageHandler.Mode mode) {
|
||||
@@ -132,7 +110,7 @@ public class GallerySpider implements GalleryProvider, SpiderQueen.SpiderListene
|
||||
|
||||
if (mSpiderQueen == null) {
|
||||
mSpiderQueen = new SpiderQueen(sHttpClient, sSpiderInfoDir,
|
||||
mGalleryBase, mMode, mDownloadDirParent, mDownloadDirname, this);
|
||||
mGalleryBase, mMode, new GalleryDir(mGalleryBase), this);
|
||||
mThreadFactory.newThread(mSpiderQueen).start();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ package com.hippo.ehviewer.gallery;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Pair;
|
||||
import android.webkit.MimeTypeMap;
|
||||
@@ -46,7 +45,6 @@ import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||
|
||||
public class ImageHandler {
|
||||
|
||||
@@ -58,12 +56,10 @@ public class ImageHandler {
|
||||
|
||||
private static SimpleDiskCache sDiskCache;
|
||||
|
||||
private int mPages;
|
||||
private GalleryBase mGalleryBase;
|
||||
private UniFile mDownloadDirParent;
|
||||
private String mDownloadDirname;
|
||||
private @Nullable UniFile mDownloadDir;
|
||||
private GalleryDir mGalleryDir;
|
||||
private volatile Mode mMode;
|
||||
private AtomicReferenceArray<String> mFilenames;
|
||||
private BitmapPool mBitmapPool = new BitmapPool();
|
||||
|
||||
public enum Mode {
|
||||
@@ -75,54 +71,25 @@ public class ImageHandler {
|
||||
sDiskCache = diskCache;
|
||||
}
|
||||
|
||||
ImageHandler(GalleryBase galleryBase, int pages, Mode mode, UniFile downloadDirParent, String downloadDirname) {
|
||||
ImageHandler(GalleryBase galleryBase, int pages, Mode mode, GalleryDir galleryDir) {
|
||||
mGalleryBase = galleryBase;
|
||||
mMode = mode;
|
||||
mFilenames = new AtomicReferenceArray<>(pages);
|
||||
mDownloadDirParent = downloadDirParent;
|
||||
mDownloadDirname = downloadDirname;
|
||||
|
||||
mGalleryDir = galleryDir;
|
||||
mPages = pages;
|
||||
if (mode == Mode.DOWNLOAD) {
|
||||
mDownloadDir = mDownloadDirParent.createDirectory(mDownloadDirname);
|
||||
mGalleryDir.ensureUniFile();
|
||||
mGalleryDir.ensureFilenames(pages);
|
||||
}
|
||||
}
|
||||
|
||||
public void setMode(Mode mode) {
|
||||
if (mMode != mode) {
|
||||
mMode = mode;
|
||||
mDownloadDir = mDownloadDirParent.createDirectory(mDownloadDirname);
|
||||
}
|
||||
// Let DownloadManager to set spiderObj's download to true
|
||||
}
|
||||
|
||||
private static String getImageFilename(int index, String extension) {
|
||||
return String.format("%08d.%s", index + 1, extension);
|
||||
}
|
||||
|
||||
private String guessImageFilename(int index) {
|
||||
if (mDownloadDir == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (String extension : POSSIBLE_IMAGE_EXTENSIONS) {
|
||||
String filename = getImageFilename(index, extension);
|
||||
if (mDownloadDir.findFile(filename) != null) {
|
||||
return filename;
|
||||
if (mode == Mode.DOWNLOAD) {
|
||||
mGalleryDir.ensureUniFile();
|
||||
mGalleryDir.ensureFilenames(mPages);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private @Nullable String getImageFilename(int index) {
|
||||
String filename = mFilenames.get(index);
|
||||
if (filename == null) {
|
||||
filename = guessImageFilename(index);
|
||||
if (filename != null) {
|
||||
// Put filename into array
|
||||
mFilenames.lazySet(index, filename);
|
||||
}
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
private InputStreamPipe getReadInputStreamPipe(int index) {
|
||||
@@ -130,12 +97,8 @@ public class ImageHandler {
|
||||
return sDiskCache.getInputStreamPipe(key);
|
||||
}
|
||||
|
||||
private InputStreamPipe getDownloadInputStreamPipe(String filename) {
|
||||
if (mDownloadDir == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
UniFile uniFile = mDownloadDir.findFile(filename);
|
||||
private InputStreamPipe getDownloadInputStreamPipe(int index) {
|
||||
UniFile uniFile = mGalleryDir.getImageFile(index);
|
||||
if (uniFile != null) {
|
||||
return new UniFileInputStreamPipe(uniFile);
|
||||
} else {
|
||||
@@ -148,12 +111,8 @@ public class ImageHandler {
|
||||
return sDiskCache.getOutputStreamPipe(key);
|
||||
}
|
||||
|
||||
private OutputStreamPipe getDownloadOutputStreamPipe(String filename) {
|
||||
if (mDownloadDir == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
UniFile uniFile = mDownloadDir.createFile(filename);
|
||||
private OutputStreamPipe getDownloadOutputStreamPipe(int index) {
|
||||
UniFile uniFile = mGalleryDir.getImageFile(index);
|
||||
if (uniFile != null) {
|
||||
return new UniFileOutputStreamPipe(uniFile);
|
||||
} else {
|
||||
@@ -171,23 +130,14 @@ public class ImageHandler {
|
||||
}
|
||||
|
||||
private boolean containFromDownload(int index) {
|
||||
if (index >= mFilenames.length()) {
|
||||
if (index >= mPages) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String filename = mFilenames.get(index);
|
||||
if (filename != null) {
|
||||
// Check it in dir
|
||||
if (mDownloadDir != null && mDownloadDir.findFile(filename) != null) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
filename = guessImageFilename(index);
|
||||
if (filename != null) {
|
||||
// Put filename into array
|
||||
mFilenames.lazySet(index, filename);
|
||||
return true;
|
||||
}
|
||||
// Check it in download dir
|
||||
UniFile uniFile = mGalleryDir.findImageFile(index);
|
||||
if (uniFile != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to find image in cache
|
||||
@@ -196,10 +146,8 @@ public class ImageHandler {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mDownloadDir == null) {
|
||||
// Can't get download dir
|
||||
return false;
|
||||
}
|
||||
// Try to get filename
|
||||
String filename = mGalleryDir.getImageFilename(index);
|
||||
|
||||
// Copy image from cache to dir
|
||||
OutputStream os = null;
|
||||
@@ -218,12 +166,12 @@ public class ImageHandler {
|
||||
// Can't get extension;
|
||||
return false;
|
||||
}
|
||||
filename = getImageFilename(index, extension);
|
||||
filename = GalleryDir.generateImageFilename(index, extension);
|
||||
// Put filename into array
|
||||
mFilenames.lazySet(index, filename);
|
||||
mGalleryDir.putImageFilename(filename, index);
|
||||
}
|
||||
|
||||
UniFile file = mDownloadDir.createFile(filename);
|
||||
UniFile file = mGalleryDir.createUniFile(filename);
|
||||
if (file == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -255,16 +203,10 @@ public class ImageHandler {
|
||||
}
|
||||
|
||||
public void removeFromDownload(int index) {
|
||||
if (mDownloadDir == null) {
|
||||
return;
|
||||
}
|
||||
UniFile file = mGalleryDir.findImageFile(index);
|
||||
|
||||
for (String extension : POSSIBLE_IMAGE_EXTENSIONS) {
|
||||
String filename = getImageFilename(index, extension);
|
||||
UniFile file = mDownloadDir.findFile(filename);
|
||||
if (file != null) {
|
||||
file.delete();
|
||||
}
|
||||
if (file != null) {
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,8 +222,11 @@ public class ImageHandler {
|
||||
|
||||
if (mMode == Mode.READ) {
|
||||
osPipe = getReadOutputStreamPipe(index);
|
||||
} else if (mMode == Mode.DOWNLOAD && mDownloadDir == null) {
|
||||
return;
|
||||
} else if (mMode == Mode.DOWNLOAD) {
|
||||
mGalleryDir.ensureUniFile();
|
||||
if (mGalleryDir.getDir() == null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (helper.mCancel) {
|
||||
@@ -298,8 +243,8 @@ public class ImageHandler {
|
||||
request.setOSPipe(osPipe);
|
||||
} else if (mMode == Mode.DOWNLOAD) {
|
||||
// Let download listener to fix filename
|
||||
request.setFilename(getImageFilename(index, "jpg"));
|
||||
request.setDir(mDownloadDir);
|
||||
request.setFilename(GalleryDir.generateImageFilename(index, "jpg"));
|
||||
request.setDir(mGalleryDir.getDir());
|
||||
}
|
||||
|
||||
request.setListener(downloadListener);
|
||||
@@ -307,18 +252,7 @@ public class ImageHandler {
|
||||
|
||||
if (downloadListener.mException != null) {
|
||||
// Remove failed stuff
|
||||
if (mMode == Mode.READ) {
|
||||
sDiskCache.remove(EhCacheKeyFactory.getImageKey(mGalleryBase.gid, index));
|
||||
} else if (mMode == Mode.DOWNLOAD) {
|
||||
String filename = getImageFilename(index);
|
||||
if (filename != null) {
|
||||
UniFile file = mDownloadDir.findFile(filename);
|
||||
if (file != null) {
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
remove(index);
|
||||
throw downloadListener.mException;
|
||||
}
|
||||
}
|
||||
@@ -343,7 +277,7 @@ public class ImageHandler {
|
||||
} else {
|
||||
filename = FileUtils.getNameFromFilename(oldFilename) + '.' + newExtension;
|
||||
}
|
||||
mFilenames.lazySet(mIndex, filename);
|
||||
mGalleryDir.putImageFilename(filename, mIndex);
|
||||
return filename;
|
||||
}
|
||||
|
||||
@@ -371,10 +305,7 @@ public class ImageHandler {
|
||||
if (mMode == Mode.READ) {
|
||||
isPipe = getReadInputStreamPipe(index);
|
||||
} else if (mMode == Mode.DOWNLOAD) {
|
||||
String filename = getImageFilename(index);
|
||||
if (filename != null) {
|
||||
isPipe = getDownloadInputStreamPipe(filename);
|
||||
}
|
||||
isPipe = getDownloadInputStreamPipe(index);
|
||||
}
|
||||
|
||||
if (isPipe == null) {
|
||||
@@ -418,10 +349,7 @@ public class ImageHandler {
|
||||
isPipe.close();
|
||||
is = new TempFileInputStream(tempFile);
|
||||
} else if (mMode == Mode.DOWNLOAD) {
|
||||
if (mDownloadDir == null) {
|
||||
throw new IOException("Can't find download dir");
|
||||
}
|
||||
UniFile uniFile = mDownloadDir.findFile(getImageFilename(index));
|
||||
UniFile uniFile = mGalleryDir.findImageFile(index);
|
||||
if (uniFile == null) {
|
||||
throw new IOException("Can't find image file");
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ package com.hippo.ehviewer.gallery;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Process;
|
||||
import android.util.Log;
|
||||
|
||||
import com.hippo.ehviewer.client.EhConfig;
|
||||
import com.hippo.ehviewer.client.EhUrl;
|
||||
@@ -68,8 +67,7 @@ public class SpiderQueen implements Runnable {
|
||||
public EhHttpClient mHttpClient;
|
||||
public File mSpiderInfoDir;
|
||||
public GalleryBase mGalleryBase;
|
||||
private UniFile mDownloadDirparent;
|
||||
private String mDownloadDirname;
|
||||
public GalleryDir mGalleryDir;
|
||||
public ImageHandler mImageHandler;
|
||||
public int mSource;
|
||||
private ImageHandler.Mode mMode;
|
||||
@@ -108,14 +106,13 @@ public class SpiderQueen implements Runnable {
|
||||
private final Object mGetSizeLock = new Object();
|
||||
|
||||
public SpiderQueen(EhHttpClient httpClient, File spiderInfoDir,
|
||||
GalleryBase galleryBase, ImageHandler.Mode mode, UniFile downloadDirParent,
|
||||
String downloadDirname, SpiderListener listener) {
|
||||
GalleryBase galleryBase, ImageHandler.Mode mode, GalleryDir galleryDir,
|
||||
SpiderListener listener) {
|
||||
mHttpClient = httpClient;
|
||||
mSpiderInfoDir = spiderInfoDir;
|
||||
mGalleryBase = galleryBase;
|
||||
mMode = mode;
|
||||
mDownloadDirparent = downloadDirParent;
|
||||
mDownloadDirname = downloadDirname;
|
||||
mGalleryDir = galleryDir;
|
||||
mSpiderListener = listener;
|
||||
|
||||
mSource = Settings.getEhSource();
|
||||
@@ -278,14 +275,10 @@ public class SpiderQueen implements Runnable {
|
||||
|
||||
private SpiderInfo readSpiderInfoFromDownloadDir() {
|
||||
if (mMode == ImageHandler.Mode.DOWNLOAD) {
|
||||
UniFile dir = mDownloadDirparent.findFile(mDownloadDirname);
|
||||
if (dir == null || !dir.isDirectory()) {
|
||||
// Can't get download dir
|
||||
return null;
|
||||
}
|
||||
mGalleryDir.ensureUniFile();
|
||||
|
||||
SpiderInfo spiderInfo;
|
||||
UniFile file = dir.findFile(SPIDER_FILENAME);
|
||||
UniFile file = mGalleryDir.findUniFile(SPIDER_FILENAME);
|
||||
if (file == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -322,22 +315,12 @@ public class SpiderQueen implements Runnable {
|
||||
}
|
||||
|
||||
private void writeSpiderInfoToDownloadDir(SpiderInfo spiderInfo) {
|
||||
|
||||
Log.d("TAG", "writeSpiderInfoToDownloadDir");
|
||||
|
||||
if (mMode == ImageHandler.Mode.DOWNLOAD) {
|
||||
UniFile dir = mDownloadDirparent.findFile(mDownloadDirname);
|
||||
if (dir == null || !dir.isDirectory()) {
|
||||
// Can't get download dir
|
||||
return;
|
||||
}
|
||||
mGalleryDir.ensureUniFile();
|
||||
|
||||
OutputStream os = null;
|
||||
try {
|
||||
|
||||
Log.d("TAG", "do writeSpiderInfoToDownloadDir");
|
||||
|
||||
UniFile file = dir.findFile(SPIDER_FILENAME);
|
||||
UniFile file = mGalleryDir.createUniFile(SPIDER_FILENAME);
|
||||
if (file != null) {
|
||||
os = file.openOutputStream();
|
||||
spiderInfo.write(os);
|
||||
@@ -578,7 +561,7 @@ public class SpiderQueen implements Runnable {
|
||||
mPageStates[i] = PAGE_STATE_NONE;
|
||||
}
|
||||
mSpiderWorkers = new SpiderWorker[3];
|
||||
mImageHandler = new ImageHandler(gb, spiderInfo.pages, mMode, mDownloadDirparent, mDownloadDirname);
|
||||
mImageHandler = new ImageHandler(gb, spiderInfo.pages, mMode, mGalleryDir);
|
||||
// Check stop
|
||||
if (mStop) {
|
||||
return;
|
||||
|
||||
Reference in new issue
Block a user