<commit_before>import Foundation
import Alamofire

open class DownloadManager {
  public enum ClienType {
    case audioKnigi, audioBoo
  }

  public init() {}

  public func download(clientType: ClienType, url: String) throws {
    switch clientType {
      case .audioKnigi:
        try downloadAudioKnigiTracks(url)
      case .audioBoo:
        try downloadAudioBooTracks(url)
    }
  }

  public func downloadAudioKnigiTracks(_ url: String) throws {
    let client = AudioKnigiAPI()

    let audioTracks = try client.getAudioTracks(url)
    let bookDir = URL(string: url)!.lastPathComponent

    var currentAlbum: String?

    for track in audioTracks {
      print(track)

      if !track.albumName.isEmpty {
        currentAlbum = track.albumName
      }

      let path = track.url
      let name = track.title

      let encodedPath = path.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)!

      let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]

      let fileURL = documentsURL.appendingPathComponent(bookDir)
        .appendingPathComponent(currentAlbum ?? "")
        .appendingPathComponent("\(name).mp3")

      downloadTrack(from: encodedPath, to: fileURL)
    }
  }

  public func downloadAudioBooTracks(_ url: String) throws {
    let client = AudioBooAPI()

    let playlistUrls = try client.getPlaylistUrls(url)

    if playlistUrls.count > 0 {
      let playlistUrl = playlistUrls[0]

      let audioTracks = try client.getAudioTracks(playlistUrl)
      var bookDir = URL(string: url)!.lastPathComponent
      bookDir = String(bookDir[...bookDir.index(bookDir.endIndex, offsetBy: -".html".count-1)])

      for track in audioTracks {
        print(track)

        let path = "\(AudioBooAPI.ArchiveUrl)\(track.sources[0].file)"
        let name = track.orig

        let encodedPath = path.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)!

        let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]

        let fileURL = documentsURL.appendingPathComponent(bookDir).appendingPathComponent("\(name).mp3")

        downloadTrack(from: encodedPath, to: fileURL)
      }
    }
    else {
      print("Cannot find playlist.")
    }
  }

  func downloadTrack(from: String, to: URL) {
    let utilityQueue = DispatchQueue.global(qos: .utility)

    let semaphore = DispatchSemaphore.init(value: 0)

    if Files.exist(to.path) {
      print("\(to.path) --- exist")

      return
    }

    let destination: DownloadRequest.DownloadFileDestination = { _, _ in
      return (to, [.removePreviousFile, .createIntermediateDirectories])
    }

    Alamofire.download(from, to: destination)
      .downloadProgress(queue: utilityQueue) { progress in
        //print("Download Progress: \(progress.fractionCompleted)")
      }
      .responseData(queue: utilityQueue) { response in
        if let url = response.destinationURL {
          FileManager.default.createFile(atPath: url.path, contents: response.result.value)<commit_msg>add download manager<commit_after>import Foundation
import Alamofire

open class DownloadManager {
  public enum ClienType {
    case audioKnigi, audioBoo
  }

  public init() {}

  public func download(clientType: ClienType, url: String) throws {
    switch clientType {
      case .audioKnigi:
        try downloadAudioKnigiTracks(url)
      case .audioBoo:
        try downloadAudioBooTracks(url)
    }
  }

  public func downloadAudioKnigiTracks(_ url: String) throws {
    let client = AudioKnigiAPI()

    let audioTracks = try client.getAudioTracks(url)
    let bookDir = URL(string: url)!.lastPathComponent

    var currentAlbum: String?

    for track in audioTracks {
      print(track)

      if !track.albumName.isEmpty {
        currentAlbum = track.albumName
      }

      let path = track.url
      let name = track.title

      let encodedPath = path.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)!

      let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]

      let fileURL = documentsURL.appendingPathComponent(bookDir)
        .appendingPathComponent(currentAlbum ?? "")
        .appendingPathComponent("\(name).mp3")

      downloadTrack(from: encodedPath, to: fileURL)
    }
  }

  public func downloadAudioBooTracks(_ url: String) throws {
    let client = AudioBooAPI()

    let playlistUrls = try client.getPlaylistUrls(url)

    if playlistUrls.count > 0 {
      let playlistUrl = playlistUrls[0]

      let audioTracks = try client.getAudioTracks(playlistUrl)
      var bookDir = URL(string: url)!.lastPathComponent
      bookDir = String(bookDir[...bookDir.index(bookDir.endIndex, offsetBy: -".html".count-1)])

      for track in audioTracks {
        print(track)

        let path = "\(AudioBooAPI.ArchiveUrl)\(track.sources[0].file)"
        let name = track.orig

        let encodedPath = path.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)!

        let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]

        let fileURL = documentsURL.appendingPathComponent(bookDir).appendingPathComponent("\(name)")

        downloadTrack(from: encodedPath, to: fileURL)
      }
    }
    else {
      print("Cannot find playlist.")
    }
  }

  func downloadTrack(from: String, to: URL) {
    let utilityQueue = DispatchQueue.global(qos: .utility)

    let semaphore = DispatchSemaphore.init(value: 0)

    if Files.exist(to.path) {
      print("\(to.path) --- exist")

      return
    }

    let destination: DownloadRequest.DownloadFileDestination = { _, _ in
      return (to, [.removePreviousFile, .createIntermediateDirectories])
    }

    Alamofire.download(from, to: destination)
      .downloadProgress(queue: utilityQueue) { progress in
        //print("Download Progress: \(progress.fractionCompleted)")
      }
      .responseData(queue: utilityQueue) { response in
        if let url = response.destinationURL {
          FileManager.default.createFile(atPath: url.path, contents: response.result.value)
{'fraction_non_alphanumeric': 0.09972433922490676, 'fraction_numerical': 0.002756607750932382, 'mean_word_length': 3.1845318860244234, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 32, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2347127', 'n_tokens_mistral': 1867, 'n_tokens_neox': 1787, 'n_words': 395}