├── .gitignore ├── LICENSE ├── OnlyFansDL.sln ├── OnlyFansDL ├── ApiDefinition.cs ├── Core │ ├── Main.cs │ └── Requester.cs ├── Models │ └── User.cs ├── OnlyFansDL.csproj ├── Program.cs └── Requests │ ├── BaseRequest.cs │ ├── DownloadRequest.cs │ ├── PhotosRequest.cs │ ├── ProfileRequest.cs │ └── VideosRequest.cs └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.toptal.com/developers/gitignore/api/rider,csharp,dotnetcore 3 | # Edit at https://www.toptal.com/developers/gitignore?templates=rider,csharp,dotnetcore 4 | 5 | ### Csharp ### 6 | ## Ignore Visual Studio temporary files, build results, and 7 | ## files generated by popular Visual Studio add-ons. 8 | ## 9 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 10 | 11 | # User-specific files 12 | *.rsuser 13 | *.suo 14 | *.user 15 | *.userosscache 16 | *.sln.docstates 17 | 18 | # User-specific files (MonoDevelop/Xamarin Studio) 19 | *.userprefs 20 | 21 | # Mono auto generated files 22 | mono_crash.* 23 | 24 | # Build results 25 | [Dd]ebug/ 26 | [Dd]ebugPublic/ 27 | [Rr]elease/ 28 | [Rr]eleases/ 29 | x64/ 30 | x86/ 31 | [Aa][Rr][Mm]/ 32 | [Aa][Rr][Mm]64/ 33 | bld/ 34 | [Bb]in/ 35 | [Oo]bj/ 36 | [Ll]og/ 37 | [Ll]ogs/ 38 | 39 | # Visual Studio 2015/2017 cache/options directory 40 | .vs/ 41 | # Uncomment if you have tasks that create the project's static files in wwwroot 42 | #wwwroot/ 43 | 44 | # Visual Studio 2017 auto generated files 45 | Generated\ Files/ 46 | 47 | # MSTest test Results 48 | [Tt]est[Rr]esult*/ 49 | [Bb]uild[Ll]og.* 50 | 51 | # NUnit 52 | *.VisualState.xml 53 | TestResult.xml 54 | nunit-*.xml 55 | 56 | # Build Results of an ATL Project 57 | [Dd]ebugPS/ 58 | [Rr]eleasePS/ 59 | dlldata.c 60 | 61 | # Benchmark Results 62 | BenchmarkDotNet.Artifacts/ 63 | 64 | # .NET Core 65 | project.lock.json 66 | project.fragment.lock.json 67 | artifacts/ 68 | 69 | # StyleCop 70 | StyleCopReport.xml 71 | 72 | # Files built by Visual Studio 73 | *_i.c 74 | *_p.c 75 | *_h.h 76 | *.ilk 77 | *.meta 78 | *.obj 79 | *.iobj 80 | *.pch 81 | *.pdb 82 | *.ipdb 83 | *.pgc 84 | *.pgd 85 | *.rsp 86 | *.sbr 87 | *.tlb 88 | *.tli 89 | *.tlh 90 | *.tmp 91 | *.tmp_proj 92 | *_wpftmp.csproj 93 | *.log 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*[.json, .xml, .info] 147 | 148 | # Visual Studio code coverage results 149 | *.coverage 150 | *.coveragexml 151 | 152 | # NCrunch 153 | _NCrunch_* 154 | .*crunch*.local.xml 155 | nCrunchTemp_* 156 | 157 | # MightyMoose 158 | *.mm.* 159 | AutoTest.Net/ 160 | 161 | # Web workbench (sass) 162 | .sass-cache/ 163 | 164 | # Installshield output folder 165 | [Ee]xpress/ 166 | 167 | # DocProject is a documentation generator add-in 168 | DocProject/buildhelp/ 169 | DocProject/Help/*.HxT 170 | DocProject/Help/*.HxC 171 | DocProject/Help/*.hhc 172 | DocProject/Help/*.hhk 173 | DocProject/Help/*.hhp 174 | DocProject/Help/Html2 175 | DocProject/Help/html 176 | 177 | # Click-Once directory 178 | publish/ 179 | 180 | # Publish Web Output 181 | *.[Pp]ublish.xml 182 | *.azurePubxml 183 | # Note: Comment the next line if you want to checkin your web deploy settings, 184 | # but database connection strings (with potential passwords) will be unencrypted 185 | *.pubxml 186 | *.publishproj 187 | 188 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 189 | # checkin your Azure Web App publish settings, but sensitive information contained 190 | # in these scripts will be unencrypted 191 | PublishScripts/ 192 | 193 | # NuGet Packages 194 | *.nupkg 195 | # NuGet Symbol Packages 196 | *.snupkg 197 | # The packages folder can be ignored because of Package Restore 198 | **/[Pp]ackages/* 199 | # except build/, which is used as an MSBuild target. 200 | !**/[Pp]ackages/build/ 201 | # Uncomment if necessary however generally it will be regenerated when needed 202 | #!**/[Pp]ackages/repositories.config 203 | # NuGet v3's project.json files produces more ignorable files 204 | *.nuget.props 205 | *.nuget.targets 206 | 207 | # Microsoft Azure Build Output 208 | csx/ 209 | *.build.csdef 210 | 211 | # Microsoft Azure Emulator 212 | ecf/ 213 | rcf/ 214 | 215 | # Windows Store app package directories and files 216 | AppPackages/ 217 | BundleArtifacts/ 218 | Package.StoreAssociation.xml 219 | _pkginfo.txt 220 | *.appx 221 | *.appxbundle 222 | *.appxupload 223 | 224 | # Visual Studio cache files 225 | # files ending in .cache can be ignored 226 | *.[Cc]ache 227 | # but keep track of directories ending in .cache 228 | !?*.[Cc]ache/ 229 | 230 | # Others 231 | ClientBin/ 232 | ~$* 233 | *~ 234 | *.dbmdl 235 | *.dbproj.schemaview 236 | *.jfm 237 | *.pfx 238 | *.publishsettings 239 | orleans.codegen.cs 240 | 241 | # Including strong name files can present a security risk 242 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 243 | #*.snk 244 | 245 | # Since there are multiple workflows, uncomment next line to ignore bower_components 246 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 247 | #bower_components/ 248 | 249 | # RIA/Silverlight projects 250 | Generated_Code/ 251 | 252 | # Backup & report files from converting an old project file 253 | # to a newer Visual Studio version. Backup files are not needed, 254 | # because we have git ;-) 255 | _UpgradeReport_Files/ 256 | Backup*/ 257 | UpgradeLog*.XML 258 | UpgradeLog*.htm 259 | ServiceFabricBackup/ 260 | *.rptproj.bak 261 | 262 | # SQL Server files 263 | *.mdf 264 | *.ldf 265 | *.ndf 266 | 267 | # Business Intelligence projects 268 | *.rdl.data 269 | *.bim.layout 270 | *.bim_*.settings 271 | *.rptproj.rsuser 272 | *- [Bb]ackup.rdl 273 | *- [Bb]ackup ([0-9]).rdl 274 | *- [Bb]ackup ([0-9][0-9]).rdl 275 | 276 | # Microsoft Fakes 277 | FakesAssemblies/ 278 | 279 | # GhostDoc plugin setting file 280 | *.GhostDoc.xml 281 | 282 | # Node.js Tools for Visual Studio 283 | .ntvs_analysis.dat 284 | node_modules/ 285 | 286 | # Visual Studio 6 build log 287 | *.plg 288 | 289 | # Visual Studio 6 workspace options file 290 | *.opt 291 | 292 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 293 | *.vbw 294 | 295 | # Visual Studio LightSwitch build output 296 | **/*.HTMLClient/GeneratedArtifacts 297 | **/*.DesktopClient/GeneratedArtifacts 298 | **/*.DesktopClient/ModelManifest.xml 299 | **/*.Server/GeneratedArtifacts 300 | **/*.Server/ModelManifest.xml 301 | _Pvt_Extensions 302 | 303 | # Paket dependency manager 304 | .paket/paket.exe 305 | paket-files/ 306 | 307 | # FAKE - F# Make 308 | .fake/ 309 | 310 | # CodeRush personal settings 311 | .cr/personal 312 | 313 | # Python Tools for Visual Studio (PTVS) 314 | __pycache__/ 315 | *.pyc 316 | 317 | # Cake - Uncomment if you are using it 318 | # tools/** 319 | # !tools/packages.config 320 | 321 | # Tabs Studio 322 | *.tss 323 | 324 | # Telerik's JustMock configuration file 325 | *.jmconfig 326 | 327 | # BizTalk build output 328 | *.btp.cs 329 | *.btm.cs 330 | *.odx.cs 331 | *.xsd.cs 332 | 333 | # OpenCover UI analysis results 334 | OpenCover/ 335 | 336 | # Azure Stream Analytics local run output 337 | ASALocalRun/ 338 | 339 | # MSBuild Binary and Structured Log 340 | *.binlog 341 | 342 | # NVidia Nsight GPU debugger configuration file 343 | *.nvuser 344 | 345 | # MFractors (Xamarin productivity tool) working folder 346 | .mfractor/ 347 | 348 | # Local History for Visual Studio 349 | .localhistory/ 350 | 351 | # BeatPulse healthcheck temp database 352 | healthchecksdb 353 | 354 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 355 | MigrationBackup/ 356 | 357 | # Ionide (cross platform F# VS Code tools) working folder 358 | .ionide/ 359 | 360 | ### DotnetCore ### 361 | # .NET Core build folders 362 | bin/ 363 | obj/ 364 | 365 | # Common node modules locations 366 | /node_modules 367 | /wwwroot/node_modules 368 | 369 | ### Rider ### 370 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 371 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 372 | 373 | # User-specific stuff 374 | .idea 375 | .idea/** 376 | .idea/**/workspace.xml 377 | .idea/**/tasks.xml 378 | .idea/**/usage.statistics.xml 379 | .idea/**/dictionaries 380 | .idea/**/shelf 381 | 382 | # Generated files 383 | .idea/**/contentModel.xml 384 | 385 | # Sensitive or high-churn files 386 | .idea/**/dataSources/ 387 | .idea/**/dataSources.ids 388 | .idea/**/dataSources.local.xml 389 | .idea/**/sqlDataSources.xml 390 | .idea/**/dynamic.xml 391 | .idea/**/uiDesigner.xml 392 | .idea/**/dbnavigator.xml 393 | 394 | # Gradle 395 | .idea/**/gradle.xml 396 | .idea/**/libraries 397 | 398 | # Gradle and Maven with auto-import 399 | # When using Gradle or Maven with auto-import, you should exclude module files, 400 | # since they will be recreated, and may cause churn. Uncomment if using 401 | # auto-import. 402 | # .idea/artifacts 403 | # .idea/compiler.xml 404 | # .idea/jarRepositories.xml 405 | # .idea/modules.xml 406 | # .idea/*.iml 407 | # .idea/modules 408 | # *.iml 409 | # *.ipr 410 | 411 | # CMake 412 | cmake-build-*/ 413 | 414 | # Mongo Explorer plugin 415 | .idea/**/mongoSettings.xml 416 | 417 | # File-based project format 418 | *.iws 419 | 420 | # IntelliJ 421 | out/ 422 | 423 | # mpeltonen/sbt-idea plugin 424 | .idea_modules/ 425 | 426 | # JIRA plugin 427 | atlassian-ide-plugin.xml 428 | 429 | # Cursive Clojure plugin 430 | .idea/replstate.xml 431 | 432 | # Crashlytics plugin (for Android Studio and IntelliJ) 433 | com_crashlytics_export_strings.xml 434 | crashlytics.properties 435 | crashlytics-build.properties 436 | fabric.properties 437 | 438 | # Editor-based Rest Client 439 | .idea/httpRequests 440 | 441 | # Android studio 3.1+ serialized cache file 442 | .idea/caches/build_file_checksums.ser 443 | 444 | # End of https://www.toptal.com/developers/gitignore/api/rider,csharp,dotnetcore -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 MrWh1teR0se 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /OnlyFansDL.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OnlyFansDL", "OnlyFansDL\OnlyFansDL.csproj", "{D4B35AFD-7F05-4153-BAEE-F2DDC7DD4023}" 4 | EndProject 5 | Global 6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 7 | Debug|Any CPU = Debug|Any CPU 8 | Release|Any CPU = Release|Any CPU 9 | EndGlobalSection 10 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 11 | {D4B35AFD-7F05-4153-BAEE-F2DDC7DD4023}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 12 | {D4B35AFD-7F05-4153-BAEE-F2DDC7DD4023}.Debug|Any CPU.Build.0 = Debug|Any CPU 13 | {D4B35AFD-7F05-4153-BAEE-F2DDC7DD4023}.Release|Any CPU.ActiveCfg = Release|Any CPU 14 | {D4B35AFD-7F05-4153-BAEE-F2DDC7DD4023}.Release|Any CPU.Build.0 = Release|Any CPU 15 | EndGlobalSection 16 | EndGlobal 17 | -------------------------------------------------------------------------------- /OnlyFansDL/ApiDefinition.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace OnlyFansDL 3 | { 4 | public class ApiDefinition 5 | { 6 | public string Endpoint { get; set; } = "https://onlyfans.com/api2/v2/"; 7 | public string AppToken { get; set; } = "33d57ade8c02dbc5a333db99ff9ae26a"; 8 | public string UserEndpoint { get; set; } = "users/"; 9 | public string ProfileEndpoint { get; set; } = "me"; 10 | 11 | public override string ToString() 12 | { 13 | return $"{Endpoint}"; 14 | } 15 | 16 | 17 | public string GetPhotosUrl(string userId) 18 | { 19 | return $"{UserEndpoint}{userId}/posts/photos?app-token={AppToken}"; 20 | } 21 | 22 | public string GetVideosUrl(string userId) 23 | { 24 | return $"{UserEndpoint}{userId}/posts/videos?app-token={AppToken}"; 25 | } 26 | 27 | public string GetUserProfileUrl() 28 | { 29 | return $"{UserEndpoint}{ProfileEndpoint}?app-token={AppToken}";; 30 | } 31 | 32 | public string GetSpecificUserUrl(string userName) 33 | { 34 | return $"{UserEndpoint}{userName}?app-token={AppToken}"; 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /OnlyFansDL/Core/Main.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text.RegularExpressions; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | using OnlyFansDL.Models; 9 | using OnlyFansDL.Requests; 10 | using RestSharp; 11 | 12 | namespace OnlyFansDL.Core 13 | { 14 | public class Main 15 | { 16 | public ApiDefinition ApiDefinition { get; set; } = new ApiDefinition(); 17 | public Requester Requester { get; set; } 18 | public string AuthToken { get; set; } 19 | public User User { get; set; } = new User(); 20 | 21 | public KeyValuePair[] Dirs { get; set; } 22 | 23 | public dynamic RequestedProfile { get; set; } 24 | 25 | public Main() 26 | { 27 | Requester = new Requester(ApiDefinition.Endpoint); 28 | } 29 | 30 | public async Task Start() 31 | { 32 | WelcomeMessage(); 33 | GetAuthToken(); 34 | 35 | if (String.IsNullOrEmpty(AuthToken)) 36 | { 37 | Console.ForegroundColor = ConsoleColor.Red; 38 | Console.WriteLine("no AuthToken provided"); 39 | Console.ResetColor(); 40 | return; 41 | } 42 | 43 | 44 | var ownProfile = new ProfileRequest(ApiDefinition.GetUserProfileUrl(), AuthToken).Create(); 45 | var result = Requester.SendRequest(ownProfile); 46 | 47 | User.Id = result["id"]; 48 | User.Username = result["name"]; 49 | 50 | if (!String.IsNullOrEmpty(User.Username)) 51 | { 52 | Console.WriteLine("own Account found!"); 53 | Console.ForegroundColor = ConsoleColor.Green; 54 | Console.WriteLine($"{User.Username} / {User.Id}"); 55 | Console.ResetColor(); 56 | } 57 | 58 | var userName = GetUserName(); 59 | 60 | var requestProfile = new ProfileRequest(ApiDefinition.GetSpecificUserUrl(userName), AuthToken).Create(); 61 | RequestedProfile = Requester.SendRequest(requestProfile); 62 | 63 | 64 | if (RequestedProfile == null) return; 65 | 66 | string photos = Convert.ToString(RequestedProfile["photosCount"]); 67 | string videos = Convert.ToString(RequestedProfile["videosCount"]); 68 | var totalPosts = RequestedProfile["postsCount"]; 69 | var id = RequestedProfile["id"]; 70 | Console.ForegroundColor = ConsoleColor.Yellow; 71 | Console.WriteLine(""); 72 | Console.WriteLine($"=== User informations ({userName} / {id})"); 73 | Console.WriteLine(""); 74 | Console.WriteLine($"total posts: {totalPosts}"); 75 | Console.WriteLine($"total videos: {videos}"); 76 | Console.WriteLine($"total photos: {photos}"); 77 | Console.ResetColor(); 78 | 79 | 80 | Console.WriteLine("[OnlyFansDL] > creating folder structure..."); 81 | if (!CreateUserFolderStructure(userName)) 82 | { 83 | return; 84 | } 85 | 86 | Console.WriteLine("[OnlyFansDL] > folder structure created."); 87 | string strId = Convert.ToString(id); 88 | var photosRequest = new PhotosRequest(ApiDefinition.GetPhotosUrl(strId), AuthToken).Create(99999); 89 | var photoPosts = Requester.SendRequest(photosRequest); 90 | 91 | var videosRequest = new VideosRequest(ApiDefinition.GetVideosUrl(strId), AuthToken).Create(99999); 92 | var videosPosts = Requester.SendRequest(videosRequest); 93 | 94 | Console.WriteLine(); 95 | Console.ForegroundColor = ConsoleColor.Green; 96 | Console.WriteLine("=== Photos Download started ==="); 97 | await SaveMaterial(photoPosts, photos); 98 | Console.WriteLine(); 99 | Console.WriteLine("=== Videos Download started ==="); 100 | await SaveMaterial(videosPosts, videos); 101 | Console.WriteLine(); 102 | Console.ResetColor(); 103 | 104 | } 105 | 106 | private async Task SaveMaterial(dynamic collection, string count) 107 | { 108 | var counter = 1; 109 | foreach (dynamic data in collection) 110 | { 111 | var media = data["media"]; 112 | if (media == null) 113 | { 114 | continue; 115 | } 116 | 117 | foreach (var material in media) 118 | { 119 | string type = Convert.ToString(material["type"]); 120 | string cdnUrl = Convert.ToString(material["full"]); 121 | bool canView = material["canView"]; 122 | 123 | var requester = new Requester(cdnUrl); 124 | KeyValuePair path = new KeyValuePair(); 125 | 126 | switch (type.ToLower()) 127 | { 128 | case "photo": 129 | { 130 | if (canView) 131 | { 132 | path = Dirs.SingleOrDefault(a => a.Key == "PhotosDir"); 133 | } 134 | 135 | break; 136 | } 137 | case "video": 138 | { 139 | if (canView) 140 | { 141 | path = Dirs.SingleOrDefault(a => a.Key == "VideoDir"); 142 | } 143 | 144 | break; 145 | } 146 | } 147 | 148 | if (path.Key == null) 149 | { 150 | continue; 151 | } 152 | 153 | var names = Regex.Matches(cdnUrl.ToLower(), @"[\w-]+\.(jpg|png|mp4|mov|jpeg)"); 154 | var fileName = names[0].Groups[0].Value; 155 | 156 | if (!File.Exists(path.Value + $"/{fileName}")) 157 | { 158 | var request = new DownloadRequest(AuthToken).Create(); 159 | requester.DownloadContent(request,path.Value,fileName); 160 | if (path.Key == "PhotosDir") 161 | { 162 | Thread.Sleep(TimeSpan.FromSeconds(0.1)); 163 | } 164 | } 165 | 166 | counter++; 167 | Console.Write($"\rDownloaded: {counter} / {count}"); 168 | } 169 | } 170 | } 171 | 172 | private bool CreateUserFolderStructure(string username) 173 | { 174 | var baseDir = System.AppContext.BaseDirectory; 175 | var basePath = baseDir + $"{username}"; 176 | 177 | if (!Directory.Exists(baseDir + $"{username}")) 178 | { 179 | Directory.CreateDirectory(baseDir + $"{username}"); 180 | } 181 | 182 | if (!Directory.Exists(basePath + "/videos")) 183 | { 184 | Directory.CreateDirectory(basePath + "videos"); 185 | } 186 | 187 | if (!Directory.Exists(basePath + "/photos")) 188 | { 189 | Directory.CreateDirectory(basePath + "photos"); 190 | } 191 | 192 | Dirs = GetDirs(username); 193 | 194 | 195 | return true; 196 | } 197 | 198 | private KeyValuePair[] GetDirs(string username) 199 | { 200 | var baseDir = System.AppContext.BaseDirectory; 201 | var basePath = baseDir + $"{username}"; 202 | 203 | return new KeyValuePair[] 204 | { 205 | new("BaseDir", basePath), 206 | new("VideoDir", $"{basePath}/videos"), 207 | new("PhotosDir", $"{basePath}/photos"), 208 | }; 209 | } 210 | 211 | private string GetUserName() 212 | { 213 | Console.WriteLine(); 214 | Console.WriteLine("please, enter the username: "); 215 | var userName = Console.ReadLine(); 216 | return !String.IsNullOrEmpty(userName) ? userName : throw new Exception("No username was given!"); 217 | } 218 | 219 | private void GetAuthToken() 220 | { 221 | Console.WriteLine("[OnlyFansDL] please Enter your AuthToken > "); 222 | AuthToken = Console.ReadLine(); 223 | } 224 | 225 | private void WelcomeMessage() 226 | { 227 | Console.WriteLine("===== OnlyFans Downloader ====="); 228 | Console.WriteLine(""); 229 | Console.WriteLine("Repository: "); 230 | Console.ForegroundColor = ConsoleColor.Red; 231 | Console.WriteLine("this tool is for educational purposes only"); 232 | Console.WriteLine(""); 233 | Console.WriteLine(""); 234 | Console.ResetColor(); 235 | } 236 | } 237 | } -------------------------------------------------------------------------------- /OnlyFansDL/Core/Requester.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using OnlyFansDL.Requests; 3 | using RestSharp; 4 | 5 | namespace OnlyFansDL.Core 6 | { 7 | public class Requester 8 | { 9 | public RestClient Client { get; set; } 10 | 11 | public Requester(string baseUrl) 12 | { 13 | Client = new RestClient(baseUrl); 14 | Client.UserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36"; 15 | } 16 | 17 | public dynamic SendRequest(T request) where T : IRestRequest 18 | { 19 | return Client.Get(request).Data; 20 | } 21 | 22 | public void DownloadContent(T request, string filePath, string fileName) where T : IRestRequest 23 | { 24 | 25 | var tempFile = filePath + $"/{fileName}"; 26 | using var writer = File.OpenWrite(tempFile); 27 | 28 | request.ResponseWriter = responseStream => 29 | { 30 | using (responseStream) 31 | { 32 | responseStream.CopyTo(writer); 33 | } 34 | }; 35 | 36 | 37 | Client.DownloadData(request); 38 | } 39 | 40 | } 41 | } -------------------------------------------------------------------------------- /OnlyFansDL/Models/User.cs: -------------------------------------------------------------------------------- 1 | namespace OnlyFansDL.Models 2 | { 3 | public class User 4 | { 5 | public string Username { get; set; } 6 | public long Id { get; set; } 7 | } 8 | } -------------------------------------------------------------------------------- /OnlyFansDL/OnlyFansDL.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net5.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /OnlyFansDL/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using OnlyFansDL.Core; 3 | 4 | namespace OnlyFansDL 5 | { 6 | class Program 7 | { 8 | 9 | static void Main(string[] args) 10 | { 11 | Core.Main main = new Main(); 12 | main.Start().GetAwaiter().GetResult(); 13 | Console.WriteLine("==== DONE! - enjoy ur content ====="); 14 | } 15 | 16 | } 17 | } -------------------------------------------------------------------------------- /OnlyFansDL/Requests/BaseRequest.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using RestSharp; 3 | 4 | namespace OnlyFansDL.Requests 5 | { 6 | public class BaseRequest 7 | { 8 | public string AuthToken { get; set; } 9 | public RestRequest Request { get; set; } 10 | 11 | public BaseRequest(string uri, string authToken) 12 | { 13 | AuthToken = authToken; 14 | Request = new RestRequest(uri); 15 | } 16 | 17 | public void SetHeaders() 18 | { 19 | Request.AddHeaders(new List>() 20 | { 21 | new("Accept", " application/json, text/plain, */*"), 22 | new("Accept-Encoding", " gzip, deflate"), 23 | new("access-token", AuthToken), 24 | }); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /OnlyFansDL/Requests/DownloadRequest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | using RestSharp; 5 | 6 | namespace OnlyFansDL.Requests 7 | { 8 | public class DownloadRequest : BaseRequest 9 | { 10 | public DownloadRequest(string authToken,string uri = "" ) : base(uri, authToken) 11 | { 12 | AuthToken = authToken; 13 | 14 | Request = new RestRequest(); 15 | } 16 | 17 | public IRestRequest Create() 18 | { 19 | return Request; 20 | } 21 | 22 | 23 | } 24 | } -------------------------------------------------------------------------------- /OnlyFansDL/Requests/PhotosRequest.cs: -------------------------------------------------------------------------------- 1 | using RestSharp; 2 | 3 | namespace OnlyFansDL.Requests 4 | { 5 | public class PhotosRequest : BaseRequest 6 | { 7 | 8 | public int Limit { get; set; } 9 | 10 | public PhotosRequest(string uri, string authToken) : base(uri, authToken) 11 | { 12 | AuthToken = authToken; 13 | Request = new RestRequest(uri); 14 | } 15 | 16 | public RestRequest Create(int limit) 17 | { 18 | this.Limit = limit; 19 | SetHeaders(); 20 | SetQueryParams(); 21 | return Request; 22 | } 23 | 24 | private void SetQueryParams() 25 | { 26 | //limit=6&order=publish_date_desc&skip_users=all&skip_users_dups=1&only_can_view=1&pinned_sort=0 27 | Request.AddQueryParameter("limit", Limit.ToString()); 28 | Request.AddQueryParameter("order", "publish_date_desc"); 29 | Request.AddQueryParameter("skip_users", "all"); 30 | Request.AddQueryParameter("skip_users_dups", "1"); 31 | Request.AddQueryParameter("only_can_view", "1"); 32 | Request.AddQueryParameter("pinned_sort", "0"); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /OnlyFansDL/Requests/ProfileRequest.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using RestSharp; 3 | 4 | namespace OnlyFansDL.Requests 5 | { 6 | public class ProfileRequest : BaseRequest 7 | { 8 | public ProfileRequest(string uri, string authToken) : base(uri, authToken) 9 | { 10 | AuthToken = authToken; 11 | Request = new RestRequest(uri); 12 | } 13 | 14 | 15 | public RestRequest Create() 16 | { 17 | SetHeaders(); 18 | 19 | return Request; 20 | } 21 | 22 | private void SetHeaders() 23 | { 24 | Request.AddHeaders(new List>() 25 | { 26 | new("Accept", " application/json, text/plain, */*"), 27 | new("Accept-Encoding", " gzip, deflate"), 28 | new("access-token", AuthToken), 29 | }); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /OnlyFansDL/Requests/VideosRequest.cs: -------------------------------------------------------------------------------- 1 | using RestSharp; 2 | 3 | namespace OnlyFansDL.Requests 4 | { 5 | public class VideosRequest : BaseRequest 6 | { 7 | 8 | public int Limit { get; set; } 9 | 10 | public VideosRequest(string uri, string authToken) : base(uri, authToken) 11 | { 12 | AuthToken = authToken; 13 | Request = new RestRequest(uri); 14 | } 15 | 16 | public RestRequest Create(int limit) 17 | { 18 | this.Limit = limit; 19 | SetHeaders(); 20 | SetQueryParams(); 21 | return Request; 22 | } 23 | 24 | private void SetQueryParams() 25 | { 26 | //limit=6&order=publish_date_desc&skip_users=all&skip_users_dups=1&only_can_view=1&pinned_sort=0 27 | Request.AddQueryParameter("limit", Limit.ToString()); 28 | Request.AddQueryParameter("order", "publish_date_desc"); 29 | Request.AddQueryParameter("skip_users", "all"); 30 | Request.AddQueryParameter("skip_users_dups", "1"); 31 | Request.AddQueryParameter("only_can_view", "1"); 32 | Request.AddQueryParameter("pinned_sort", "0"); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Onlyfans DL (.NET Core) 2 | 3 | This tool downloads all photos/videos from an OnlyFans profile, creating a local archive. 4 | 5 | You must be subscribed to the profile to download their content. 6 | OnlyFansDL (.NET Core) creates a directory in the repo directory that corresponds to the profile you download. Each profile you download is created as a root directory. Within each profile directory, all media is downloaded in photos/ and videos/. 7 | 8 | 9 | ### Built With 10 | 11 | * [.NET Core](https://github.com/dotnet/core) 12 | * [RestSharp](https://restsharp.dev/) 13 | * [Rider](https://www.jetbrains.com/rider/) 14 | 15 | ## Disclaimer 16 |

17 | This repository is for research purposes only, the use of this code is your responsibility. 18 | I take NO responsibility and/or liability for how you choose to use any of the source code available here. By using any of the files available in this repository, you understand that you are AGREEING TO USE AT YOUR OWN RISK. Once again, ALL files available here are for EDUCATION and/or RESEARCH purposes ONLY. 19 |

20 | 21 | 22 | ## Getting Started 23 | 24 | To get a local copy up and running follow these simple steps. 25 | 26 | ### Installation 27 | 28 | 1. Clone the repo 29 | ```sh 30 | git clone https://github.com/MrWh1teR0se/OnlyFansDL.git 31 | ``` 32 | 2. Install NuGet packages 33 | ```sh 34 | dotnet restore 35 | ``` 36 | 37 | ## Usage 38 | 39 | 1. start the Program (Debug/Release) 40 | 2. Go to [OnlyFans](https://onlyfans.com) and login with your Credentials 41 | 42 | 2.1 copy your AuthToken (open the Developer-Console > Console ) 43 | ```js 44 | copy(localStorage.getItem("accessToken")) 45 | OR 46 | localStorage.getItem("accessToken") 47 | ``` 48 | 3. enter your AccessToken and press [ENTER] 49 | 50 | 3.1 if the authentication was successful the username and the UserID appears as green output text: 51 | USERNAME / USERID 52 | 53 | 4. enter the username of the OnlyFans model/actor whose content you wish to download. 54 | 5. wait and let the magic begins 55 | 56 | ## Contributing 57 | 58 | Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**. 59 | 60 | 1. Fork the Project 61 | 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`) 62 | 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`) 63 | 4. Push to the Branch (`git push origin feature/AmazingFeature`) 64 | 5. Open a Pull Request 65 | 66 | 67 | 68 | 69 | ## License 70 | 71 | Distributed under the MIT License. See `LICENSE` for more information. 72 | --------------------------------------------------------------------------------