├── VOffline ├── Models │ ├── Vk │ │ ├── VkToken.cs │ │ └── VkCredentials.cs │ ├── Google │ │ ├── GoogleCheckIn.cs │ │ ├── ProtobufField.cs │ │ └── GoogleCredentials.cs │ ├── Mode.cs │ ├── Storage │ │ ├── NetworkException.cs │ │ ├── IDownload.cs │ │ ├── PlaylistWithAudio.cs │ │ ├── Download.cs │ │ └── AlbumWithPhoto.cs │ └── Settings.cs ├── Services │ ├── Storage │ │ ├── CreateMode.cs │ │ ├── DownloadQueueProvider.cs │ │ ├── BackgroundDownloader.cs │ │ ├── AttachmentProcessor.cs │ │ └── FilesystemTools.cs │ ├── Handlers │ │ ├── IHandler.cs │ │ ├── CommentHandler.cs │ │ ├── WallHandler.cs │ │ ├── HandlerBase.cs │ │ ├── CommentsHandler.cs │ │ ├── PlaylistHandler.cs │ │ ├── AlbumHandler.cs │ │ ├── PostHandler.cs │ │ ├── PhotoHandler.cs │ │ └── AudioHandler.cs │ ├── VkNetHacks │ │ ├── LimitedSizeStack.cs │ │ ├── SimpleLoggerProvider.cs │ │ ├── SimpleLogger.cs │ │ ├── CancellableConstraint.cs │ │ └── CustomRestClient.cs │ ├── Token │ │ ├── TokenMagic.cs │ │ ├── Vk │ │ │ ├── VkTokenReceiver.cs │ │ │ └── VkHttpRequests.cs │ │ └── Google │ │ │ ├── AndroidAuth.cs │ │ │ ├── VarInt.cs │ │ │ ├── ProtobufParser.cs │ │ │ ├── MTalk.cs │ │ │ └── GoogleHttpRequests.cs │ ├── Extensions.cs │ ├── FileCache.cs │ ├── Logic.cs │ └── Vk │ │ ├── AttachmentExtensions.cs │ │ └── VkApiUtils.cs ├── appsettings.json ├── log4net.config ├── VOffline.csproj └── Program.cs ├── README.md ├── VOffline.sln └── .gitignore /VOffline/Models/Vk/VkToken.cs: -------------------------------------------------------------------------------- 1 | namespace VOffline.Models.Vk 2 | { 3 | public class VkToken 4 | { 5 | public string Token { get; set; } 6 | } 7 | } -------------------------------------------------------------------------------- /VOffline/Models/Google/GoogleCheckIn.cs: -------------------------------------------------------------------------------- 1 | namespace VOffline.Models.Google 2 | { 3 | public class GoogleCheckIn 4 | { 5 | public byte[] Response { get; set; } 6 | } 7 | } -------------------------------------------------------------------------------- /VOffline/Models/Mode.cs: -------------------------------------------------------------------------------- 1 | namespace VOffline.Models 2 | { 3 | public enum Mode 4 | { 5 | Wall, 6 | Audio, 7 | Photos, 8 | Video, 9 | Docs, 10 | All 11 | } 12 | } -------------------------------------------------------------------------------- /VOffline/Models/Vk/VkCredentials.cs: -------------------------------------------------------------------------------- 1 | namespace VOffline.Models.Vk 2 | { 3 | public class VkCredentials 4 | { 5 | public string Login { get; set; } 6 | public string Password { get; set; } 7 | } 8 | } -------------------------------------------------------------------------------- /VOffline/Services/Storage/CreateMode.cs: -------------------------------------------------------------------------------- 1 | namespace VOffline.Services.Storage 2 | { 3 | public enum CreateMode 4 | { 5 | AutoRenameCollisions, 6 | ThrowIfExists, 7 | OverwriteExisting 8 | } 9 | } -------------------------------------------------------------------------------- /VOffline/Models/Google/ProtobufField.cs: -------------------------------------------------------------------------------- 1 | namespace VOffline.Models.Google 2 | { 3 | public class ProtobufField 4 | { 5 | public ProtobufField(int value) 6 | { 7 | Type = value & 0x7; // last three bits, 0b00000111 8 | FieldNumber = value >> 3; 9 | } 10 | 11 | public int Type { get; } 12 | public int FieldNumber { get; } 13 | } 14 | } -------------------------------------------------------------------------------- /VOffline/Services/Handlers/IHandler.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using log4net; 5 | 6 | namespace VOffline.Services.Handlers 7 | { 8 | public interface IHandler 9 | { 10 | Task Process(T data, DirectoryInfo parentDir, CancellationToken token, ILog log); 11 | DirectoryInfo GetWorkingDirectory(T data, DirectoryInfo parentDir); 12 | } 13 | } -------------------------------------------------------------------------------- /VOffline/Models/Storage/NetworkException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace VOffline.Models.Storage 4 | { 5 | public class NetworkException : ApplicationException 6 | { 7 | public NetworkException(string message, Exception innerException) : base(message, innerException) 8 | { 9 | } 10 | 11 | public NetworkException(string message) : base(message) 12 | { 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /VOffline/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Settings": { 3 | //"Targets": [ "id1", "durov", "public147415323", "tech" ], 4 | //"Targets": [ "retrowave" ], 5 | //"Targets": ["rast1234", "retrowave"], 6 | //"Modes": [ "Audio", "Wall" ], 7 | //"Modes": [ "Photos" ], 8 | //"Modes": [ "All" ], 9 | "OutputPath": "." 10 | }, 11 | "VkCredentials": { 12 | //"Login": "username@gmail.com", 13 | //"Password": "your_vk_password" 14 | } 15 | } -------------------------------------------------------------------------------- /VOffline/Models/Google/GoogleCredentials.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace VOffline.Models.Google 4 | { 5 | public class GoogleCredentials 6 | { 7 | public long Id { get; set; } 8 | public long Token { get; set; } 9 | public List RawId { get; set; } 10 | 11 | public override string ToString() 12 | { 13 | return $"{nameof(GoogleCredentials)}(id {Id}; token {Token})"; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VOffline 2 | Evacuate from VK! 🚚 3 | 4 | #### This tool can save almost everything from public VK content (wall, posts, comments, photos, polls). Audio and playlists too! 5 | 6 | 7 | It works fine but needs some polishing and documentation is not yet done. 8 | To start, look at `appsettings.json`, it is pretty self explanatory. For now you will need Visual Studio to buld and run the thing. 9 | 10 | ___ 11 | All interested in token for Audio API have look at https://github.com/Rast1234/VkNet.TokenMagic 12 | -------------------------------------------------------------------------------- /VOffline/Models/Storage/IDownload.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | 7 | namespace VOffline.Models.Storage 8 | { 9 | public interface IDownload 10 | { 11 | DirectoryInfo Location { get; } 12 | string DesiredName { get; } 13 | int RetryCount { get; } 14 | IReadOnlyList Errors { get; } 15 | void AddError(Exception e); 16 | Task GetContent(CancellationToken token); 17 | } 18 | } -------------------------------------------------------------------------------- /VOffline/Services/VkNetHacks/LimitedSizeStack.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace VOffline.Services.VkNetHacks 4 | { 5 | public class LimitedSizeStack : LinkedList 6 | { 7 | private readonly int _maxSize; 8 | 9 | public LimitedSizeStack(int maxSize) 10 | { 11 | this._maxSize = maxSize; 12 | } 13 | 14 | public void Push(T item) 15 | { 16 | this.AddFirst(item); 17 | if (this.Count <= this._maxSize) 18 | return; 19 | this.RemoveLast(); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /VOffline/Services/VkNetHacks/SimpleLoggerProvider.cs: -------------------------------------------------------------------------------- 1 | using log4net; 2 | using Microsoft.Extensions.Logging; 3 | 4 | namespace VOffline.Services.VkNetHacks 5 | { 6 | public class SimpleLoggerProvider : ILoggerProvider 7 | { 8 | private readonly SimpleLogger logger; 9 | 10 | public SimpleLoggerProvider(ILog log) 11 | { 12 | logger = new SimpleLogger(log); 13 | } 14 | 15 | public void Dispose() 16 | { 17 | } 18 | 19 | public ILogger CreateLogger(string categoryName) 20 | { 21 | return logger; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /VOffline/Services/Storage/DownloadQueueProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using Microsoft.Extensions.Options; 6 | using Nito.AsyncEx; 7 | using VOffline.Models; 8 | using VOffline.Models.Storage; 9 | 10 | namespace VOffline.Services.Storage 11 | { 12 | public class DownloadQueueProvider 13 | { 14 | public DownloadQueueProvider(IOptionsSnapshot settings) 15 | { 16 | var queueSizeLimit = settings.Value.DownloadQueueLimit; 17 | Pending = queueSizeLimit > 0 18 | ? new AsyncProducerConsumerQueue(settings.Value.DownloadQueueLimit) 19 | : new AsyncProducerConsumerQueue(); 20 | } 21 | 22 | public async Task EnqueueAll(IEnumerable items, CancellationToken token) 23 | { 24 | await Task.WhenAll(items.Select(async x => await Pending.EnqueueAsync(x, token))); 25 | } 26 | 27 | public AsyncProducerConsumerQueue Pending { get; } 28 | } 29 | } -------------------------------------------------------------------------------- /VOffline/Models/Storage/PlaylistWithAudio.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using VkNet.Model.Attachments; 5 | 6 | namespace VOffline.Models.Storage 7 | { 8 | public class PlaylistWithAudio 9 | { 10 | public AudioPlaylist Playlist { get; } 11 | public IReadOnlyList