(w http.ResponseWriter, req DownloadRequest)
| 175 | } |
| 176 | |
| 177 | func (s *Server) handlePlanInternal(w http.ResponseWriter, req DownloadRequest) { |
| 178 | if req.Repo == "" { |
| 179 | writeError(w, http.StatusBadRequest, "Missing required field: repo", "") |
| 180 | return |
| 181 | } |
| 182 | |
| 183 | // Parse filters from repo:filter syntax |
| 184 | if strings.Contains(req.Repo, ":") && len(req.Filters) == 0 { |
| 185 | parts := strings.SplitN(req.Repo, ":", 2) |
| 186 | req.Repo = parts[0] |
| 187 | if parts[1] != "" { |
| 188 | for _, f := range strings.Split(parts[1], ",") { |
| 189 | f = strings.TrimSpace(f) |
| 190 | if f != "" { |
| 191 | req.Filters = append(req.Filters, f) |
| 192 | } |
| 193 | } |
| 194 | } |
| 195 | } |
| 196 | |
| 197 | revision := req.Revision |
| 198 | if revision == "" { |
| 199 | revision = "main" |
| 200 | } |
| 201 | |
| 202 | // Create job for scanning |
| 203 | dlJob := hfdownloader.Job{ |
| 204 | Repo: req.Repo, |
| 205 | Revision: revision, |
| 206 | IsDataset: req.Dataset, |
| 207 | Filters: req.Filters, |
| 208 | Excludes: req.Excludes, |
| 209 | ExactMatch: req.ExactMatch, |
| 210 | AppendFilterSubdir: req.AppendFilterSubdir, |
| 211 | } |
| 212 | |
| 213 | // Use server-configured output directory (not from request for security) |
| 214 | outputDir := s.config.ModelsDir |
| 215 | if req.Dataset { |
| 216 | outputDir = s.config.DatasetsDir |
| 217 | } |
| 218 | |
| 219 | settings := hfdownloader.Settings{ |
| 220 | OutputDir: outputDir, |
| 221 | Token: s.config.Token, |
| 222 | Endpoint: s.config.Endpoint, |
| 223 | } |
| 224 | |
| 225 | // Collect plan items |
| 226 | var files []PlanFile |
| 227 | var totalSize int64 |
| 228 | |
| 229 | progressFunc := func(evt hfdownloader.ProgressEvent) { |
| 230 | if evt.Event == "plan_item" { |
| 231 | files = append(files, PlanFile{ |
| 232 | Path: evt.Path, |
| 233 | Size: evt.Total, |
| 234 | LFS: evt.IsLFS, |
no test coverage detected